/*!
 * \file    OMS_SessionDef.hpp
 * \author  IvanS, MarkusS, PeterG, ThomasA
 * \brief   OMS session 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_SESSIONDEF_HPP
#define __OMS_SESSIONDEF_HPP

#include "Oms/OMS_Monitor.hpp"
#include "Oms/OMS_BeforeImageList.hpp"
#include "Oms/OMS_StackAllocator.hpp"
#include "Oms/OMS_VarObj.hpp"
#include "Oms/OMS_MassDerefIterators.hpp"    // PTS 1120478

#include "geo00.h"
#include "ggg251.h"
#include "ggg01.h"

class OMS_ISessionLockObjects;
class OMS_GuidEntry;
class OmsCallbackInterface;
class OmsIOidReadIterator;
class OmsIOidAppender;
class OmsAbstractObject;
class OmsObjectContainer;

/// Implements an OMS Session representing a kernel session in the OMS.
class OMS_Session {   

#ifndef USE_SYSTEM_ALLOC_CO13
  SAPDBMem_RawAllocator m_heap; // caution! must be declared prior to session member 
                                // that require the allocator
  OMS_StackAllocator        m_stackHeap;
#endif

public:
#define RESCHEDULE_DISTANCE 1000 // call dispatcher every 1000 derefs

  class MethodCallEplilogScope
  {
  public:
    MethodCallEplilogScope(OMS_Session& session);
    ~MethodCallEplilogScope();
  private:
    OMS_Session& m_session;
  };

  friend class OMS_Session::MethodCallEplilogScope;

  OMS_Session(
    IliveCacheSink* lcSink,
    int cntRegions, 
    pasbool* pToCancel,
    tsp00_TaskId taskId);
  ~OMS_Session();
  inline void* operator new(size_t sz);
#if defined(OMS_PLACEMENT_DELETE)
  inline void  operator delete(void* p);
#endif
  inline void                  ActivateDefaultContext();
  void                  AssignLcSink(IliveCacheSink* pSink); /* PTS 1109371 */
  inline void                  AddContainerInfo(OMS_ClassIdEntry* classInfo);
  inline void                  AssertNotReadOnly(const char* callerMsg);
  const  OmsObjectId&          CastOid(const ClassIDRef castToGuid, const OmsObjectId& oid);
  void                  ChangedConsistentView();
#if defined(OMSTST)
  inline void                  CheckCancelCountDown();    // PTS 1112358
  inline void                  CheckExceptionCountDown(); // PTS 1112358
#endif
  void                  CleanAfterDropSchema();
  void                  ClearDefaultContext();
  inline void                  ClearFreeLists(int caller);
  inline void                  CloseVersion();
  inline void                  CommitSubtrans(int requiredLevel);
  inline void                  ClearTransVersions();
  inline void                  CreateDefaultContext();
  void                  CreateVersion(const OmsVersionId& versionId, const OmsTypeWyde* desc);  // PTS 1117690
  inline int                   CurrentSubtransLevel() const;
  inline OMS_Context*      CurrentContext() const;
  void                  CurrentMethodCallEpilog(tsp00_Int4 runTime);
  inline void                  DecSubtransLevel();
  void                  DeleteAll(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  inline void                  DeleteSession();
  void                  DeleteVarObject(const OmsVarOid& oid);
  inline OmsAbstractObject*    DeRef (const OmsObjectId& oid, const ClassIDRef guid, bool forUpd, bool doLock);
  int                          MassDeref(OmsIDerefIter &derefIter);                            // PTS 1120478
  int                          MassDerefForUpd(OmsIDerefIterForUpd &derefIter, bool doLock);   // PTS 1120478
  int                          MassDerefViaKey(OmsIDerefKeyIter &derefIter);                            // PTS 1120478
  int                          MassDerefViaKeyForUpd(OmsIDerefKeyIterForUpd &derefIter, bool doLock);   // PTS 1120478
  inline OmsAbstractObject*    DeRefViaKey (unsigned char* key, const ClassIDRef, bool forUpd, bool do_lock, OmsSchemaHandle, OmsContainerNo);
  const  void*                 DeRefVarObject(const OmsVarOid& oid);
  void                  DropVersion(OMS_Context* context);
  void                  DropVersionEpilog(OMS_Context* context); 
  void                  DropVersionProlog(OMS_Context* context);
  void                  Dump(OMS_DumpInterface& dumpObj) const;
  inline void                  ExecuteSubtransCommit(int requiredLevel);
  inline void                  deallocate(void* p);
  inline bool                  ForceReadOnly();
  inline void                  FreeBeforeImages();
  inline void                  FreeStackHeap();
  inline OmsAbstractObject*    ForUpdPtr(OmsObjectContainer* pObj);
  inline OmsCallbackInterface* GetCallbackInterface() const;
  inline OmsCallbackInterface* GetCallbackInterface(const ClassIDRef guid) const;
  inline OMS_ClassIdEntry*     GetClsInfo(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  inline OMS_ClassIdEntry*     GetClsInfoForReg(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  inline OMS_GuidEntry*        GetClassInfo(const ClassIDRef guid);
  inline OMS_ClassIdEntry*     GetContainerInfo(tsp00_Uint4 containerHandle);
  inline OmsObjectContainer* GetMemory (OMS_ClassIdEntry&);
  inline OmsObjectContainer* GetMemory (OMS_GuidEntry& classInfo);
  inline OmsObjectContainer* GetMemoryInVersion (OMS_ClassIdEntry&);
  bool                  GetMethodCallMonitorInfo (OmsMonitorData& info) const;
  inline bool           GetReadOnly() const { return m_read_only; }
  inline OMS_ISessionLockObjects* GetSessionLockObject() const;
  inline long                  GetStoredErrorCode() const;           // PTS 1122839
  inline tsp00_TaskId          GetTaskId() const; // PTS 1110315
  inline unsigned char*        GetVarObjMemory(size_t sz);
  inline tsp00_Int4            GetVarObjSize(const OmsVarOid& oid);
  bool                  HistoryInUse(const OmsObjectId&);
  inline bool                  InVersion();
  inline void                  IncRefCnt();
  inline void                  IncSubtransLevel ();
  inline void                  IncCacheHit(const OmsObjectId& oid); // PTS 1117571
  inline void                  IncCacheMiss();                      // PTS 1117571
  inline void                  IncDeref();
  inline void                  IncDerefIter_LC(); // PTS 1107819 TA 13/09/2000  
  inline void                  IncDereflC();
  inline void                  IncDerefKey();
  inline void                  IncStore(); 
  inline void                  IncStore_lC();
  inline void                  IncOmsTerminate();
  inline void                  IncDelete (); 
  inline void                  IncDelete_lC(); 
  inline void                  IncDelete_lC(tsp00_Int4 cntDeleted); 
  inline void                  IncLock();
  inline void                  IncLogHop(int cnt); 
  inline void                  IncLogHopIter(int cnt); // PTS 1107819 TA 13/09/2000  
  inline void                  IncExceptions();
  inline void                  IncOutOfDate();
  inline void                  IncOutOfMemory();
  inline void                  IncTimeout(); 
  inline void                  IncSubtransCommit(); 
  inline void                  IncSubtransRollback(); 
  inline void                  IncLoadVarObj(); 
  inline void                  IncLoadVarObjLC(); 
  inline void                  IncStoreVarObj();
  inline void                  IncStoreVarObjLC();
  inline void                  IncReadStreamBuffer();
  inline void                  IncRehash();               // PTS 1118855
  inline void                  IncWriteStreamBuffer();
  inline void                  IncReadStreamRow();
  inline void                  IncWriteStreamRow();
  inline void                  InsertTransVersion(OMS_Context* context, bool create);
  bool                         IsLocked (const OmsObjectId& oid);
  inline OmsObjectContainer*   LoadVarObject (const OmsVarOid& oid, OMS_VarObjLockType lockReq, tsp00_Int4 size, void* buf);
  inline void                  MaxHashChainLen (int len); // PTS 1118855
  inline void                  MonitorSubtransLevel(); 
  inline void                  SetCacheSize(tsp00_Uint4 sz); 
  inline void                  IncCreateVersion (); 
  inline void                  IncOpenVersion (); 
  inline void                  IncCloseVersion (); 
  inline void                  IncDropVersion (); 
  inline void                  IncDeleteVarObject (); 
  inline void                  IncDeleteVarObjectLC (); 
  inline void                  IncCntWaitOmsLockObj();
  inline void                  IncWaitOmsLockObjSecs(tsp00_Int4);
  inline bool                  InsertBeforeImage (OmsObjectContainer* p);
  inline void                  InsertNewBeforeImage (OmsObjectContainer* p, OMS_ClassIdEntry* clsinfo);
  inline bool                  IsDefaultContext(OMS_Context* context);
  inline bool                  IsSubtransOpen();
  inline void                  LockObj(OmsObjectContainer* p);
  inline bool                  TryLockObj(OmsObjectContainer* p);
  void                         LockObjMass(OmsIOidReadIterator& oids, short& timeout, 
                                           OmsIOidAppender& errOids, bool newConsistentView = false,
                                           cgg250AvlTree<OmsObjectId,OmsObjectId,OMS_Session> *pUnlockedObjects = NULL);  // PTS 1121449
  inline void*                 allocate(size_t sz);
  inline void                  MonitorVarObjSize(tsp00_Int4);
  inline void                  MonitorWaitNewConsistentView(tsp00_Int4);
  void                  NewConsistentView(OmsIOidReadIterator& pOids, short timeout, OmsIOidAppender& pErrOids);   // PTS 1115027
  OmsAbstractObject*    NewKeyedObject(const ClassIDRef guid, const unsigned char* key, OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  OmsAbstractObject*    NewObject(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  const OmsVarOid&      NewVarObject(OmsSchemaHandle Schema, OmsContainerNo ContainerNo);
  inline void                  OpenVersion(OMS_Context* context, bool create);
  inline void                  OpenVersionProlog(const OmsVersionId &versionId, bool create);  // PTS 1129082
  inline void                  OpenVersionEpilog();  // PTS 1129082
  void                  RegContainer(OmsSchemaHandle Schema,
    const ClassIDRef   guid,
    const char*        ClassName, 
    size_t             PersistentSize,
    size_t             ObjectSize,
    const ClassIDPtr   pBaseClass,
    OmsAbstractObject* Obj, 
    OmsContainerNo     ContainerNo,
    size_t              arrayByteSize = 0);
  void                  RegVarObjectContainer(OmsSchemaHandle Schema, OmsContainerNo cno);
  void                  RegisterCallbackInterface(const ClassIDRef guid, OmsCallbackInterface* pInterface);
#if defined(OMSTST)
  inline bool                  RequiredExceptionThrown() const; // PTS 1112358
#endif
  inline void                  ResetSubtransLevel ();
  inline void                  ReleaseAllUnchanged();    // PTS 1128262
  void                  ReleaseCallbackInterface();
  inline void                  ReleaseObj(const OmsObjectId& oid);
  inline void                  ReleaseObj(OmsObjectContainer* p, bool unchangedOnly = false);
  inline void                  ReleaseObjUnconditional(const OmsObjectId& oid);
  void                  ReleaseVarObject(const OmsVarOid& oid);
  inline void                  Reschedule(); /* PTS 1107849 */  
  void                  RemoveFromTransVersion(OMS_Context* context);
  inline void                  RollbackSubtrans(int requiredLevel, bool callFromRollbackTrans);
  inline void                  SetContext(OMS_Context* context) {m_context = context;}
  void                  SetCurrentMonitorMethod(tgg01_COMMonitorInfo* p); // PTS 1107731
#if defined(OMSTST)
  inline void                  SetCancelCountDown(int countDown);
  inline void                  SetExceptionCountDown(int countDown);
#endif
  void                  SetReadOnly(bool readOnly);
  inline void                  SetSessionLockObject(OMS_ISessionLockObjects* pLockObj);
  void                  SetTimeout(short timeout);
  inline void                  Signal(tsp00_TaskId TaskId, tsp00_Bool ok); // PTS 1110315
  inline void*                 StackHeapMalloc(size_t size);
  inline int                   StartSubtrans();
  inline void                  StoreErrorCode(long errorCode);   // PTS 1122839
  inline void                  StoreVarObject (const OmsVarOid& oid, const void* pVarObj, unsigned long objLength);
  void                  ThrowDBError(tsp00_Int2 e, const char* msg, const char* pFileName, int line);
  void                  ThrowDBError(tsp00_Int2 e, const char* msg, const OmsObjectId& oid, const char* pFileName, int line);
  void                  ThrowDBError(tsp00_Int2 e, const char* msg, const OmsVersionId& v, const char* pFileName, int line);
  void                  ThrowReturnCode(tsp00_Int2 e, const char* msg, const char* pFile, unsigned int line);
  void                  Trace( const char*fmt, ... );
  void                  TransEnd();
  inline void                  TransEndEpilog();
  inline void                  UnforceReadOnly(bool);
  void                  UnlockObj (const OmsObjectId& oid);
  bool                  VersionBoundByMe(OMS_Context* context);
  void                  Wait();

  inline bool IsDataChanged() const { return m_isDataChanged; }
  inline void SetDataChanged() { m_isDataChanged = true; }

  void         Set_OidOfLastObject (const OmsObjectId &varOid){ m_varOid = varOid; }
  OmsObjectId  Get_OidOfLastObject ()                         { return m_varOid;   }            


public:
  // GUID of the callback interface
  ClassID					          m_callbackInterfaceGuid;
  /*! Pointer to a callback interface which can be used by application programmer to react 
  ** on certain events like e.g. on commit, on rollback,... */
  OmsCallbackInterface*     m_callbackInterface;
  /*! Pointer to the sink. The sink is needed for the communication with the kernel. */
  IliveCacheSink*           m_lcSink;
  OmsTypeInt64              m_sizeVarobj; 
  OmsTypeInt64              m_cntVarobj;
  /*! Duration of the lock timeout of the kernel */
  tsp00_Int4                m_timeout;
  /*! Number of COM-objects which are connected to this session */
  int                       m_refCnt;
  /*! Actual level of subtransactions. This value is incremented (resp. decremented) 
  ** every time a new subtransaction is opened (resp. closed). If there is no subtransaction 
  ** open, which means that we are working in the basic transaction, then this variable 
  ** has the value 1. */
  int                       m_subtrans_lvl;
  /*! Minimal level of subtransaction. This value is either 1 for normal liveCache or
  ** 0 for simulator, in order to force before images in main transaction. This is
  ** needed to check for updates without stores */
  int                       m_min_subtrans_lvl;
  bool                      m_stream_io;
  /*! If this variable equals true, then it is not possible to execute any changing operation 
  ** (e.g. update, delete) on persistent objects. If such operations are started, then 
  ** the execption e_oms_read_only is thrown. (This member is set to true e.g. during 
  ** certain phases of the commit and rollback handling.) */
  bool                      m_read_only;
  /*! Array to control the state of the application programmer controlled critical sections 
  ** (OmsCriticalSections). For each possible critical section there is an entry in the 
  ** array which either equals true if section is in use or false otherwise. The size 
  ** of this array (and thereby the number of critical sections) is determined via the 
  ** kernel interface when the session is created.   */
  bool*                     m_critical_section_in_use;
  /*! Similar to the critical sections this structure can be used by the application 
  ** programmers for synchronization. In contrast to critical section it is not only 
  ** possible to hold exclusive locks, but also to aquire shared locks which means, that 
  ** several task can hold the same lock. Furthermore the locks are released at the end of 
  ** the transaction. */
  OMS_ISessionLockObjects* m_lockObjects;
  /*! Pointer to the actual context which might be the default context or a version context. 
  ** If no version is open, than this pointer equals OMS_Session::m_defaultContext */
  OMS_Context*          m_context;
  /*! Pointer to the default context  */
  OMS_Context*          m_defaultContext;
  /*! Dictionary of the before images. For each open subtransaction level there exists a chain 
  ** of before images which can be used to rollback the corresponding subtransaction level. */
  OMS_BeforeImageList   m_beforeImages;  
  OMS_VarObjChunk       m_currVarObjChunk;
  /*! List of pointers to versions which are bound to this session. Although it is not 
  ** possible to have more than one version open in a session, there might be several 
  ** versions bound to a session. A version keeps bound to a session until the version 
  ** is closed and the transaction is committed or until the version is dropped. */
  cgg251DCUList<OMS_Context*,OMS_Session> m_versionsBoundToTrans;
  /*! List of versions created in this transaction. These versions may not be opened,
  ** if any changes have been made to IS-data. */
  cgg251DCUList<OMS_Context*,OMS_Session> m_createdVersionsInTrans;
  /*! List of pointers to omsHandles (COM-objects) which are connected with this session. 
  ** This list is used to call methods of the class OmsHandle. The number of entries in 
  ** this list should be equal to OMS_Session::m_refCnt. 
  ** \since PTS 1116693 */
  cgg251DCList<OmsHandle*,OMS_Session>        m_handleList;


private :
  /*! This member determines whether the private member OMS_Session::m_read_only can  
  ** be set to true or not.  */
  bool                     m_allowReadOnly;
  bool                     m_inMethodCallEpilog;
  /*! Set to true, if any IS-data have been changed in basis (e.g., omsRelease). */
  bool                     m_isDataChanged;
  /*! Aggregated monitoring information of several calls. */ 
  OMS_Monitor              m_monitor;
  /*! Monitoring information of the last call. When a new procedure call is executed, 
  ** this information is reset. */
  tgg01_COMMonitorInfo*    m_monitor_curr;

  /*! This member is set to RESCHEDULE_DISTANCE (=1000) and when a DeRef is executed 
  ** the value is decreased by one. If the value equals 0 then the 
  ** OMS_Session::m_toCancel flag is checked and a rescheduling of the process 
  ** is forced. This prevents that COM-routines are running in a loop without releasing 
  ** the CPU and thereby without the change to stop the processing. */
  int                      m_rescheduleDistance;
  /*! When a new procedure call is executed, the current heap consumption is determined 
  ** and stored in this member. This information is needed later when the heap 
  ** consumption of this procedure itself must be determined. */
  tsp00_8ByteCounter       m_heapAtMethodBegin;
  /*! This member is a pointer to the cancel flag in the kernel. As this flag is checked 
  ** regularily (see OMS_Session::m_scheduleDistance) long running transactions can 
  ** be terminated by setting this flag in the kernel. If a routine is canceled because 
  ** of this flag, then the exception e_cancelled is thrown. 
  ** \since PTS 1107849 */
  pasbool&                 m_toCancel;
  /*! Error code which can be set and recalled by the application 
  ** \see OMS_Handle::omsGetStoredErrorCode 
  ** \see OMS_Handle::omsStoreErrorCode
  ** \since PTS 1122839   */
  long                     m_errorCode;               
  /*! This id is used to identify the task which has aquired a lock resp. which is waiting 
  ** for a lock (see OMS_Session::m_lockObjects)  
  ** \since PTS 1110315 */
  tsp00_TaskId             m_taskId;  
  /// @name Only for test purposes
  //@{
  /*! This member controls at what time an exception should be thrown. 
  ** \since PTS 1112358 */ 
  int                      m_exceptionCountDown;      
  /*! This member controls at what time the cancel flag should be set. 
  ** \since PTS 1112358 */ 
  int                      m_cancelCountDown;         
  /*! This member is set to true if the countdown of OMS_Session::m_exceptionCountDown 
  ** or OMS_Session::m_cancelCountDown has reached zero and so an exeption was 
  ** thrown or the cancel flag has been set. 
  ** \since PTS 1112358 */
  bool                     m_requiredExceptionThrown; 
  //@}

  OmsObjectId    m_varOid;

  void  ReleaseLocks (OmsIOidReadIterator &oids, int cnt);  // PTS 1121449
};

#endif  // __OMS_SESSIONDEF_HPP
