/*!
 * \file    OMS_ContextDef.hpp
 * \author  IvanS, MarkusS, PeterG, ThomasA
 * \brief   OMS context definition.
 */
/*

    ========== licence begin  GPL
    Copyright (c) 2002-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 __OMS_CONTEXTDEF_HPP
#define __OMS_CONTEXTDEF_HPP

#include "ggg01.h"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_RawAllocator.hpp"
#include "Oms/OMS_OidHash.hpp"
#include "Oms/OMS_NewObjCache.hpp"
#include "Oms/OMS_ClassIdHashDef.hpp"
#include "Oms/OMS_VarObj.hpp"


class OMS_Session;
class OMS_UnknownContainerId;

/// Implements an OMS Context. 
/*! A Context is a consistent view together 
** with cached Objects belonging to this view. */
class OMS_Context {

#ifndef USE_SYSTEM_ALLOC_CO13
  /*! Allocator for default context. This allocator can not deallocate memory. For the default
  ** context, this allocator is sufficient as all the memory will be freed on commit/rollback.
  ** As versions can live longer this allocator is not used if the context belongs to a version. */
  SAPDBMem_RawAllocator m_heap; // caution! must be declared prior to m_oidDir, m_containerDir etc to
                                // ensure correct sequence of destruction
#endif

public :
  enum LockType {
    NoLock,
    Lock,
    TryLock
  };

  /*! Dictionary of the persistent objects */
  OMS_OidHash            m_oidDir;
  /*! Local dictionary for containers. This local 'copy' is used to reduce contention 
  ** on the global container. Normally for every entry there should be a corresponding 
  ** entry in the global dictionary (see OMS_Context::m_lastDropId for exceptions 
  **  of this). */
  OMS_ClassIdHash          m_containerDir;
  /*! Dictionary of those objects which are newly created in a version. This dictionary 
  ** is needed for accesses via iterator because the kernel is not informed about new 
  ** objects in versions and so the iterator would not find these objects. (ONLY RELEVANT
  ** FOR VERSION) */
  OMS_NewObjCache          m_newObjCache;
  /*! Contains the value of the consistent view in which objects from the kernel must be 
  ** read. For normal contexts the value is determined when the first object is read from 
  ** the kernel and for versions the value is set when the version is opened. */
  tgg91_TransNo            m_consistentView;
  /*! Pointer to the corresponding omsSession */
  OMS_Session*             m_session;

  OMS_Context(OMS_Session* session, const OmsVersionId* vid = NULL, const tgg01_OmsVersionContext* vctxt = NULL);
  ~OMS_Context();
  inline void                  AssignLcSink(IliveCacheSink* pSink);
  inline bool                  IsBoundToTrans() { return m_boundToTrans; }
  inline void                  CheckDBError(tsp00_Int2 e, const char* msg, const OmsObjectId& oid);
  inline void                  CheckCompatibility(const ClassIDRef, OmsObjectContainerPtr);
  inline void                  CheckIfContainerNotDropped(OMS_ClassIdEntry*);
  inline bool                  CheckOid (const OmsObjectId& oid, const ClassIDRef guid);
  inline bool                  CheckOid (const OmsVarOid& oid);
  void                  CleanContainerDir();
  inline void                  ClearObjCache();
  inline void                  CloseVersion();
  inline tsp00_Int4            CurrentVersionKey() const;
  void                  DeleteSelf();
  inline void                  DecNewObjectsToFlush();
  inline void                  DeleteObjInContext (OmsObjectContainerPtr p, OMS_ClassIdEntry*);
  void                  Dump(OMS_DumpInterface& dumpObj) const;
  void                  DumpObjCache(OmsHandle&);
  void                  EmptyObjCache(tsp00_Uint4 containerHandle = 0xFFFFFFFF);
  inline bool                  ExistsConsistentView();
  inline OmsObjectContainerPtr FindObjInContext (const OmsObjectId* pOid, bool ignoreGeneration=false);  // PTS 1125361
  inline OmsObjectContainerPtr FindVarObjInContext (const OmsObjectId& oid, OMS_VarObjLockType, unsigned long size, void* buf);
  void                  FlushObj(OmsObjectContainerPtr p);
  void                  FlushDelete (OmsObjectContainerPtr pObj, bool deleteInHash); 
  void                  FlushObjCache(bool emptyObjCache, bool adaptOidHash = true);
  void                  FlushLockUpdObj(OmsObjectContainerPtr p);
  void                  FlushVarObject (OmsObjectContainerPtr p); 
  // Begin PTS 1121449
  void                  FlushObjCacheMass(bool emptyObjectCache, bool adaptOidHash); 
  void                  FlushVarObjMass(OmsObjectContainer*& pHeadOneClass, OmsObjectContainer*& pHeadOtherClasses, 
                                        OmsObjectContainer*& pFreeList);
  void                  DeleteVarObjMass(OmsObjectContainer*& pHead, OmsObjectContainer*& pFreeList);
  // End PTS 1121449
  void                  FlushVersionObjCache();  // PTS 1122280
  inline void           deallocate(void* p);
  inline void           FreeVarObj(unsigned char* p, size_t sz);
  inline OMS_GuidEntry*    GetClassInfo(const ClassIDRef guid);
  inline OMS_ClassIdEntry* GetContainerInfo(tsp00_Uint4 containerHandle);
  inline OMS_ClassIdEntry* GetContainerInfoReg(tsp00_Uint4 containerHandle);
  inline OMS_ClassIdEntry* GetContainerInfoNoCheck(tsp00_Uint4 containerHandle);
  inline OMS_Session*      GetCurrentSession();
  inline tsp00_Int4        GetHashSize() const;
  inline OMS_Context*      GetNext() const;
  inline OMS_Context*      GetNextUnloaded() const;
  inline OmsObjectContainerPtr GetObj(const OmsObjectId& oid, bool doLock);
  inline OmsObjectContainerPtr GetObj(const ClassIDRef guid, const OmsObjectId& oid, bool doLock);
  inline OmsObjectContainerPtr GetObjFromLiveCacheBase(const OmsObjectId& oid, LockType doLock, bool mayBeVarObject = true);
  inline OmsObjectContainerPtr GetObjFromLiveCacheBase(const ClassIDRef, const OmsObjectId& oid, LockType, tgg91_PageRef *objVers = NULL);
  inline OmsObjectContainerPtr GetObjViaCachedKey(OMS_ClassIdEntry& clsinfo,    // PTS 1117571
    unsigned char* key, bool doLock);
  inline OmsObjectContainerPtr GetObjViaKey(OMS_ClassIdEntry& clsinfo, unsigned char* key, bool doLock);
  const tsp00_Date&            GetCreateDate() const { return m_date; }
  const tsp00_Time&            GetCreateTime() const { return m_time; }
  const tsp00_Date&            GetOpenDate() const { return m_lastOpenDate; }
  const tsp00_Time&            GetOpenTime() const { return m_lastOpenTime; }
  const OmsVersionId&          GetVersionId() { return m_version; }
  const OmsTypeWyde*           GetVersionDesc() const { return m_versionDesc; }  // PTS 1117690
  inline int                   GetVarObjFromLiveCacheBase(const OmsObjectId& oid, bool);
  inline void                  IncNewObjectsToFlush();
  inline void                  IncVersionKey ();
  bool                         IsDropped() const { return m_isDropped; }
  bool                         IsMarked() { return m_marked; } 
  inline bool                  IsVersionOid (const OmsObjectId& oid) const;   // PTS 1117571
  inline bool                  IsVersionOpen();
  inline bool                  IsOpenVersion (const OmsVersionId& versionId);
  inline bool                  IsUnloadable();
  inline bool                  IsUnloaded() const { return (m_pVersionContext != NULL); }
  inline bool                  IsVersion();
  IliveCacheSink*              LcSink() const { return m_currLcSink; }
  // PTS 1120478
  inline int                   LoadObjsFromLiveCacheBase(int noOfOid, const OmsObjectId *pOid,  tgg91_PageRef *pObjVers,
                                 bool doLock, OmsObjectContainer **ppObjContainer, tgg00_BasisError *pDBError, OmsAbstractObject **ppObj, 
                                 OMS_GuidEntry **ppClassInfo, tgg01_ContainerId *pContainerId, int *pObjSize);
  inline int                   LoadBaseClsObjsFromLiveCacheBase(int noOfOid, const OmsObjectId *pOid, tgg91_PageRef *pObjVers,
                                 bool doLock, OmsObjectContainer **ppObjContainer, tgg00_BasisError *pDBError, OmsAbstractObject **ppObj,
                                 OMS_GuidEntry **ppClassInfo, tgg01_ContainerId *pContainerId, int *pObjSize);
  // PTS 1122194
  inline int                   LoadObjsViaKeyFromLCBase(int noOfObj, tsp00_Int4 *pKeyLen, unsigned char **ppBinaryKey,
                                 OmsObjectId *pOid, tgg91_PageRef *pObjVers, bool doLock, OmsObjectContainer **ppObjContainer, 
                                 tgg00_BasisError *pDBError, OmsAbstractObject **ppObj, OMS_ClassIdEntry **ppClsInfo, tgg01_ContainerId *pContainerId, 
                                 int *pObjSize);
  inline OmsObjectContainerPtr LoadVarObject (const OmsVarOid& oid, OMS_VarObjLockType, tsp00_Int4 objSize, OMS_VarObjChunk& chunk, void* buf);
  inline void                  LockObj(const OmsObjectId&oid);
  inline bool                  TryLockObj(const OmsObjectId&oid);
  inline void                  LockResult (tsp00_Int2 DBError, OmsObjectContainerPtr p, const OmsObjectId& oid, const char* msg); 
  inline void                  LockResult (int cnt, tsp00_Int2* DBError, OmsObjectContainer** p, const OmsObjectId *pOid, const char* msg); // PTS 1121449
  void                         LockObjWithBeforeImage();   // PTS 1128108
  inline bool                  TryLockResult (tsp00_Int2 DBError, OmsObjectContainerPtr p, const OmsObjectId& oid, const char* msg); 
  inline void*                 allocate(size_t sz);
  void                         MarkBoundToTrans() { m_boundToTrans = true; }
  void                         MarkDropped() { m_isDropped = true; }
  void                         MarkNotBoundToTrans(bool callFromDestructor);
  void                         MarkVersion() { m_marked = true; }
  void                         NewConsistentView();
  void                         OpenVersion(OMS_Session* session);
  inline void                  PutObjectIntoContext (OmsObjectContainerPtr p, tsp00_Uint4 ContainerHandle);
  inline bool                  PutObjectIntoContextReg (OmsObjectContainerPtr p, tsp00_Uint4 ContainerHandle);
  inline OmsObjectContainerPtr ReactivateReplacedVersion(OmsObjectContainer* p);   // PTS 1125361
  void                         ReleaseAllUnchanged();   // PTS 1128262
  inline void                  RenameVersion(const OmsVersionId& OldId, const OmsVersionId& NewId);
  void                         ReduceHeapUsage(); /* PTS 1109340 */
  inline void                  ResetNewObjectsToFlush();
  inline void                  ResetConsistentView ();
  void                         ResetLcSink();
  void                         ResetVersion(OMS_Session&); /* PTS 1115134 */
  inline void                  RemoveUnlockedObjFromCache();
  inline void                  SetConsistentView(const tgg91_TransNo&);
  void                         SetVersionDesc(const OmsTypeWyde*);       // PTS 1117690
  inline void                  SetNext(OMS_Context*);
  inline void                  SetNextUnloaded(OMS_Context*);
  void                         UnLoad();
  void                         VersionClearObjCache();
  inline unsigned char*        VersionContext();
  OmsObjectId           VersionNewOid();
  inline void*                 operator new(size_t sz);
#if defined(OMS_PLACEMENT_DELETE)
  inline void                  operator delete (void* p);
#endif
  inline tsp00_8ByteCounter    HeapUsed();
  tgg00_FileId&         VersionFile()    { return m_versionContext.ovc_tree; }
  tgg00_FileId&         VersionInvFile() { return m_versionContext.ovc_index_tree; }

private :
  /*! This member is used to recognize differences between the local and the global 
  ** container dictionary. If the member OMS_ContainerInfo::m_dropId of the global container 
  ** entry is larger than this member, a container has been dropped in the global container 
  ** and therefore the local container is checked whether all the entries still have a 
  ** corresponding entry in the global dictionary. If not these entries are deleted. */
  tsp00_Uint4              m_lastDropId;
  /*! Creation date of the context */
  tsp00_Date               m_date;
  /*! Creation time of the context */
  tsp00_Time               m_time;
  /*! Pointer to the sink. The sink is needed for the communication with the kernel. If 
  ** the context belongs to a version which is currently not bound to a session, then 
  ** the pointer equals NULL. */
  IliveCacheSink*          m_currLcSink;
  //IliveCacheSink*          m_sysLcSink; 
  /*! This counter is increased when new objects are created and it is decreased/reset if 
  ** the corresponding objects are flushed. This counter is only used for checking purposes 
  ** during the flush. (There is one exception in which a new object will not increase 
  ** this counter, namely if a new object has been created, then is dropped and is  
  ** created again without flushing the cache in between. In this case the section creation 
  ** will not be counted.)
  ** \since PTS 1115545 */
  int                      m_cntNewObjectsToFlush;    

  /// @name Only relevant if context belongs to a version
  //@{
  /*! Name of the version  */
  OmsVersionId             m_version;
  /*! Description of the b*-tree in which the persistent objects are stored when a 
  ** version is unloaded. */
  tgg01_OmsVersionContext  m_versionContext;
  /*! If a version is not unloaded then this pointer equals NULL; otherwise it contains the 
  ** address of OMS_Context::m_versionContext.(So this pointer can be used to determine   
  ** whether a version is unloaded or not.) */
  tgg01_OmsVersionContext* m_pVersionContext;
  /*! Pointer to another version. This pointer is used to chain the entries in the
  **  version directory hash. */
  OMS_Context*             m_next;
  /*! Pointer to another version. Normally this pointer equals NULL. Only those versions which are not 
  ** allowed to be unloaded are linked together using this pointer. */
  OMS_Context*             m_nextUnloaded;
  /*! Is version open, which means is version bound to a session and active? */
  bool                     m_isOpen;
  /*! If the deletion of the version fails with an error-code -5001, then the version is 
  ** marked as deleted. Later when accessing this version again this flag is recognized 
  ** and then the deletion is triggered again. The deletion can fail because this operation 
  ** is done outside of the critical section (because of contention/performance issues) */
  bool                     m_isDropped;
  /*! Does the context belong to a version? */
  bool                     m_isVersion;
  /*! Is this version bound to a session? This member ensures that a version is only open 
  ** in one session. (see OMS_Session::m_versionsBoundToTrans) */
  bool                     m_boundToTrans;
  /*! The version is marked by a call of OmsHandle::omsMarkVersion. This flag is only used
  ** by the application programmer and is not considered in the oms-layer */
  bool                     m_marked;
  /*! Date of the last opening of the version */
  tsp00_Date               m_lastOpenDate;
  /*! Time of the last opening of the version */
  tsp00_Time               m_lastOpenTime;
  /*! A null-terminated string which contains the (unicode) description of the version. 
  ** If no description exists, then the member equals NULL.
  ** \since PTS 1117690 */
  OmsTypeWyde*             m_versionDesc;               
  //@}
};

typedef OMS_Context* OMS_ContextPtr;

#endif // __OMS_CONTEXTDEF_HPP
