Logo Search packages:      
Sourcecode: maxdb-7.5.00 version File versions

OMS_Session.cpp

Go to the documentation of this file.
/*!
 * \file    OMS_Session.cpp
 * \author  IvanS, MarkusSi, PeterG
 * \brief   OMS session implementation
 */
/*

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


*/


#include "Oms/OMS_Session.hpp"
#include "Oms/OMS_DumpInterface.hpp"
#include "Oms/OMS_CallbackInterface.hpp"
#include "Oms/OMS_Handle.hpp"
#include "Oms/OMS_ContainerDictionary.hpp"
#include "Oms/OMS_ObjectContainer.hpp"
#include "Oms/OMS_Defines.h"
#include "hsp77.h"      // PTS 1125307
#include "geo573.h"     // needed for BAD_ALLOC_GEO573

/*----------------------------------------------------------------------*/

static
OMS_ContainerInfo* omsRegisterContainer (IliveCacheSink*        lcSink, 
                                           const ClassIDRef       guid, 
                                           const char*            ClassName, 
                                           size_t                 PersistentSize, 
                                           size_t                 ObjectSize, 
                                           const ClassIDPtr       pBaseClass,
                                           tsp00_Int4             keyPos,         // PTS 1122540
                                           tsp00_Int4             keyLen,         // PTS 1122540
                                           bool                   keyPartitioned, // PTS 1122540
                                           OmsSchemaHandle        sh,
                                           OmsContainerNo         cno,
                                           void*                  vtptr,
                                           size_t                 arrayByteSize = 0)
{
  return OMS_Globals::m_globalsInstance->m_classDictionary.RegisterContainer (lcSink, guid, ClassName, PersistentSize,
    ObjectSize, pBaseClass, 
    keyPos, keyLen, keyPartitioned,   // key-description
    sh, cno, vtptr, arrayByteSize); 
}

/*----------------------------------------------------------------------*/

static
bool omsDumpRequested(tsp00_Int4 errorNo)
{
  return OMS_Globals::m_globalsInstance->DumpRequested(errorNo);
}

/*----------------------------------------------------------------------*/

OMS_Session::OMS_Session
(
  IliveCacheSink* lcSink, 
  int             cntRegions,    
  pasbool*        pToCancel,
  tsp00_TaskId    taskId) 
:
  m_callbackInterface(NULL),
  m_lcSink(lcSink), m_sizeVarobj(0), m_cntVarobj(0), m_timeout(0), m_refCnt(0),
  m_subtrans_lvl(1), m_min_subtrans_lvl(OMS_Globals::m_globalsInstance->InSimulator() ? 0 : 1),
  m_stream_io(true), m_read_only(false), m_allowReadOnly(true), m_inMethodCallEpilog(false),
  m_isDataChanged(false),
  m_lockObjects(NULL),
  m_context(NULL), m_defaultContext(NULL), m_beforeImages(),
  #ifndef USE_SYSTEM_ALLOC_CO13
  m_stackHeap(),
  #endif
  m_monitor(taskId),
  m_monitor_curr(NULL),
  m_versionsBoundToTrans(NULL), m_createdVersionsInTrans(NULL),
  m_rescheduleDistance(RESCHEDULE_DISTANCE), m_heapAtMethodBegin(0),
  m_toCancel(*pToCancel), /* PTS 1107849 */
  m_taskId(taskId),
  m_exceptionCountDown(-1),
  m_cancelCountDown(-1),   
  m_requiredExceptionThrown(false),
  m_handleList(NULL),       // PTS 1116693
  m_errorCode(0)            // PTS 1122839
{
  memset(&m_callbackInterfaceGuid, 0, sizeof(m_callbackInterfaceGuid));
  int ix;
  m_lockObjects = OMS_ISessionLockObjects::Create(*this);
  m_beforeImages.init(this);
  m_versionsBoundToTrans.advise_allocator(this);
  m_createdVersionsInTrans.advise_allocator(this);
  m_handleList.advise_allocator(this);
  m_critical_section_in_use = REINTERPRET_CAST(bool*, allocate(cntRegions * sizeof(bool)));
  for (ix = 0; ix < cntRegions; ++ix) {
    m_critical_section_in_use[ix] = false;
  }
}

/*----------------------------------------------------------------------*/

OMS_Session::~OMS_Session()
{
  m_lockObjects->Destroy();
  if (this->InVersion()) {
    OMS_Context* pVersion = m_context;
    this->CloseVersion();
    pVersion->MarkNotBoundToTrans(true);
  }
  m_lcSink->SetDefaultContext(NULL);
  if (NULL != m_defaultContext) {
    m_defaultContext->DeleteSelf();
  }
  deallocate(m_critical_section_in_use);
  // Set Pointer in OmsHandles to this instance to NULL   // PTS 1116693
  for (cgg251dclIterator<OmsHandle*,OMS_Session> iter 
    = m_handleList.begin(); iter; ++iter) {
      (*iter())->m_pSession = NULL; 
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::AssignLcSink(IliveCacheSink* pSink) /* PTS 1109371 */
{
  m_lcSink = pSink;
  m_defaultContext->AssignLcSink(pSink);
  m_context->AssignLcSink(pSink);
}

/*----------------------------------------------------------------------*/

const OmsObjectId& OMS_Session::CastOid(const ClassIDRef castToGuid, const OmsObjectId& oid)
{
  if (!oid) { // Null Oid given
    return oid;
  }
  OmsObjectContainerPtr p = m_context->GetObj(oid, false);
  // PTS 1132363
  if (p == NULL){
    ThrowDBError (e_object_not_found, "OMS_Session::CastOid", oid, __MY_FILE__, __LINE__);
  }

  OMS_ClassIdEntry*     pFrom = p->GetContainerInfo(m_context);
  if (pFrom->GetGuid() == castToGuid) {
    return oid;
  }
  if (m_context->m_containerDir.IsDerivedClassOf(pFrom->GetGuid(), castToGuid)) {
    return oid;
  }
  if (m_context->m_containerDir.IsBaseClassOf(castToGuid, pFrom->GetGuid())) {
    return oid;
  }
  char msg[80];
#ifdef LIVECACHE_INTGUIDS
  //sprintf (msg, "guid : %8X", castToGuid);                  // PTS 1125307
  sp77sprintf (msg, sizeof(msg),"guid : %8X", castToGuid);    // PTS 1125307
#else
  //sprintf (msg, "guid : %8X-%4X-%4X-%1X%1X%1X%1X%1X%1X%1X%1X", castToGuid.Data1, castToGuid.Data2, castToGuid.Data3,
  //  castToGuid.Data4[0], castToGuid.Data4[1], castToGuid.Data4[2], castToGuid.Data4[3], castToGuid.Data4[4], castToGuid.Data4[5],
  //  castToGuid.Data4[6], castToGuid.Data4[7]);              // PTS 1125307
  sp77sprintf (msg, sizeof(msg),"guid : %8X-%4X-%4X-%1X%1X%1X%1X%1X%1X%1X%1X", castToGuid.Data1, castToGuid.Data2, castToGuid.Data3,
    castToGuid.Data4[0], castToGuid.Data4[1], castToGuid.Data4[2], castToGuid.Data4[3], castToGuid.Data4[4], castToGuid.Data4[5],
    castToGuid.Data4[6], castToGuid.Data4[7]);                // PTS 1125307
#endif
  this->ThrowDBError (e_incompatible_oid, msg, oid, __MY_FILE__, __LINE__);
  return oid;
}

/*----------------------------------------------------------------------*/

void OMS_Session::ChangedConsistentView()
{
  m_currVarObjChunk.Clear();
}

/*----------------------------------------------------------------------*/

void OMS_Session::CleanAfterDropSchema()
{
  m_defaultContext->m_oidDir.Clean();
  m_defaultContext->CleanContainerDir();
}

/*----------------------------------------------------------------------*/

void OMS_Session::ClearDefaultContext()
{
  m_defaultContext->ClearObjCache();
  this->ClearFreeLists(3);
  this->FreeStackHeap();
}

/*----------------------------------------------------------------------*/

bool OMS_Session::IsLocked (const OmsObjectId& oid)
{
  if (m_context->IsVersion()) {
    return true;
  }
  OmsObjectContainerPtr found = m_context->FindObjInContext (&oid);
  if ((NULL != found) && (found->LockedFlag())) {
    return true;
  }
  tgg00_BasisError         DBError;
  OMS_UnknownContainerId UnknownFileId;
  OMS_HResult hr = m_lcSink->IsLocked ((unsigned char*) &UnknownFileId, 
    REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)), &DBError);
  if (e_ok == DBError) {
    return true;
  } 
  else {
    if (e_object_not_locked == DBError) {
      return false;
    }
    else {
      this->ThrowDBError (DBError, "IsLocked", oid, __MY_FILE__, __LINE__);
    }
  }
  return false;
}

/*----------------------------------------------------------------------*/

void OMS_Session::CreateVersion(const OmsVersionId& versionId, const OmsTypeWyde* desc)
{
  const char* msg = "OMS_Session::CreateVersion";

  tsp00_Int2              DBError;
  tgg01_OmsVersionContext versionContext;
  OMS_Context*        context = NULL;

  this->IncCreateVersion   ();
  OMS_HResult hr = m_lcSink->CreateVersion (
      (unsigned char*) &m_context->m_consistentView,
      (unsigned char*) &versionContext,
      &DBError);
  if (DBError != 0) {
      this->ThrowDBError (DBError, msg, versionId, __MY_FILE__, __LINE__);
  }
  /* create a new context for the version */
  try {
    context = new OMS_Context(this, &versionId, &versionContext);
    context->NewConsistentView();
    context->ResetLcSink();

    OpenVersionProlog(versionId, true);  // PTS 1129082
    this->OpenVersion(context, true);
    OpenVersionEpilog();  // PTS 1129082 

    context->SetVersionDesc(desc);     // PTS 1117690
  }
  catch (DbpError& e) {
    if (context != NULL) {
      context->AssignLcSink(m_lcSink); // PTS 1108278
      context->DeleteSelf();
    }
    OMS_TRACE(omsTrError, m_lcSink, "Create Version Error : " << e.dbpError());
    throw e;
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::CurrentMethodCallEpilog(tsp00_Int4 runTime)
{
  m_requiredExceptionThrown = false;
  tsp00_8ByteCounter heapUsed;
  m_lcSink->GetSessionHeapUsage(heapUsed);
  if (runTime > 0) // PTS 1126796
  {
      m_monitor.SetRunTime(runTime);
  }
  if (NULL != m_monitor_curr) // PTS 1112146
  {
    m_monitor.AggregateCallStatistics(m_monitor_curr);
    OmsMonitorData info;
    const bool AllocatorOnly = true;
    m_lcSink->EvalCallStatistics(AllocatorOnly, info);
    m_monitor_curr->cmiCounters_gg00[cmiOutOfMemory] += info.m_cntOutOfMemory; // PTS 1126796
    if (info.m_cntOperatorNew > 0)
    {
      m_monitor_curr->cmiCounters_gg00[cmiMallocCnt] += info.m_cntOperatorNew;
      if (info.m_minChunkAllocated < m_monitor_curr->cmiCounters_gg00[cmiMallocMin])
      {
        m_monitor_curr->cmiCounters_gg00[cmiMallocMin] = info.m_minChunkAllocated; 
      }
      if (info.m_maxChunkAllocated > m_monitor_curr->cmiCounters_gg00[cmiMallocMax])
      {
        m_monitor_curr->cmiCounters_gg00[cmiMallocMax] = info.m_maxChunkAllocated; 
      }
      m_monitor_curr->cmiCounters_gg00[cmiMallocSum] += info.m_avgChunkAllocated * info.m_cntOperatorNew;
    }
    if (info.m_cntOperatorDelete > 0)
    {
        m_monitor_curr->cmiCounters_gg00[cmiFreeCnt] += info.m_cntOperatorDelete;
        if (info.m_minChunkDeleted < m_monitor_curr->cmiCounters_gg00[cmiFreeMin])
        {
            m_monitor_curr->cmiCounters_gg00[cmiFreeMin] = info.m_minChunkDeleted; 
        }
        if (info.m_maxChunkDeleted > m_monitor_curr->cmiCounters_gg00[cmiFreeMax])
        {
            m_monitor_curr->cmiCounters_gg00[cmiFreeMax] = info.m_maxChunkDeleted; 
        }
        m_monitor_curr->cmiCounters_gg00[cmiFreeSum] += info.m_avgChunkDeleted * info.m_cntOperatorDelete;
    }
    if ((heapUsed > m_heapAtMethodBegin) &&
        ( heapUsed > m_monitor_curr->cmiCounters_gg00[cmiCacheSize]))
            {
      m_monitor_curr->cmiCounters_gg00[cmiCacheSize] = heapUsed;
            }
    tsp00_8ByteCounter heapDelta = heapUsed - m_heapAtMethodBegin;  
    tsp00_8ByteCounter callCnt = ++m_monitor_curr->cmiCallCnt_gg00; // PTS 1133312
    if (callCnt > 0)
    {
        if (heapDelta < m_monitor_curr->cmiCounters_gg00[cmiDeltaMin])
        {
            m_monitor_curr->cmiCounters_gg00[cmiDeltaMin] = heapDelta; 
        }
        if (heapDelta > m_monitor_curr->cmiCounters_gg00[cmiDeltaMax])
        {
            m_monitor_curr->cmiCounters_gg00[cmiDeltaMax] = heapDelta;
        }
        tsp00_8ByteCounter cnt = m_monitor_curr->cmiCounters_gg00[cmiDeltaAvg];
        m_monitor_curr->cmiCounters_gg00[cmiDeltaAvg] = 
            (m_monitor_curr->cmiCounters_gg00[cmiDeltaAvg] * (callCnt - 1) + heapDelta) / callCnt;
    }
    // End PTS 1133312
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::DeleteAll(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo)
{
  const char* msg = "OMS_Session::DeleteAll"; 

  this->AssertNotReadOnly(msg);
  OMS_ClassIdEntry* clsinfo = this->GetClsInfo (guid, Schema, ContainerNo);
  tsp00_Int4  cntDeleted;
  tsp00_Int2  DBError;
  OmsTypeOid  errorOid;
  OMS_HResult hr = m_lcSink->DeleteAllObj (m_context->m_consistentView, (unsigned char*) &clsinfo->GetFileId(), m_context->VersionContext(),
    cntDeleted, DBError, errorOid);
  m_context->LockResult (DBError, NULL, *REINTERPRET_CAST(OmsObjectId*, &errorOid), msg);
  m_context->EmptyObjCache(clsinfo->GetContainerHandle());
  this->IncDelete_lC (cntDeleted);
}

/*----------------------------------------------------------------------*/

void OMS_Session::DeleteVarObject(const OmsVarOid& oid) 
{
  const char* msg = "OMS_Session::DeleteVarObject";

  this->AssertNotReadOnly(msg);
  this->IncDeleteVarObject();
  OmsObjectContainerPtr found = this->LoadVarObject(oid, VarObjExclusiveLock, -1, NULL);
  if (!found) {
    this->ThrowDBError (e_object_not_found, msg, oid, __MY_FILE__, __LINE__);
  }
  OMS_VarObjInfo* pObjInfo = REINTERPRET_CAST (OMS_VarObjInfo*, &found->m_pobj); /* PTS 1106727 */
  pObjInfo->unlock();
  if (!found->LockedFlag()) {
    if (!IsLocked(oid)) {
      this->ThrowDBError (e_object_not_locked, msg, oid, __MY_FILE__, __LINE__);
    }
  }
  if (!this->InsertBeforeImage (found)) {
    m_context->FreeVarObj(pObjInfo->m_pvobj, pObjInfo->m_vobjSize);
  }
  pObjInfo->m_pvobj     = NULL;
  pObjInfo->m_vobjSize  = 0;
  found->MarkDeleted();
  if (oid == m_currVarObjChunk.m_oid) {
    m_currVarObjChunk.Clear();
  }
}

/*----------------------------------------------------------------------*/

const  void* OMS_Session::DeRefVarObject(const OmsVarOid& oid)
{
  this->IncLoadVarObj();
  OmsObjectContainerPtr p = m_context->FindVarObjInContext(oid, VarObjShareLock, 0xFFFFFFFF, NULL);
  if (NULL == p) {
    tsp00_Uint4 objSize = m_context->GetVarObjFromLiveCacheBase(oid, false);
    p = m_context->LoadVarObject(oid, VarObjShareLock, objSize, m_currVarObjChunk, NULL);
    m_currVarObjChunk.Clear();
  }
  OMS_VarObjInfo* pObjInfo = REINTERPRET_CAST (OMS_VarObjInfo*, &p->m_pobj);
  return pObjInfo->m_pvobj;
}

/*----------------------------------------------------------------------*/

void OMS_Session::DropVersion(OMS_Context* context) 
{
  DropVersionProlog (context);
  DropVersionEpilog (context);
}

/*----------------------------------------------------------------------*/

void OMS_Session::DropVersionProlog(OMS_Context* context)
{
  const char* msg = "OMS_Session::DropVersionProlog";
  if (context->IsBoundToTrans()) {
    /* version is bound to trans, bound by myself ? */
    if ((context != CurrentContext()) && (!this->VersionBoundByMe(context))) {
      this->ThrowDBError (e_missing_privilege, msg, context->GetVersionId(), __MY_FILE__, __LINE__);
    }

    //context->CloseVersion();   // moved to Epilog  PTS 1129082

    this->RemoveFromTransVersion(context);
  }
  else {
    context->AssignLcSink(m_lcSink);
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::DropVersionEpilog(OMS_Context* context)
{
  m_beforeImages.removeContext(context);

  if (context->IsBoundToTrans()) {    // PTS 1129082
    context->CloseVersion();
  }

  /* free context */
  context->DeleteSelf();
  /* return to default context */
  this->ActivateDefaultContext();
  this->IncDropVersion();
}

/*----------------------------------------------------------------------*/

void OMS_Session::Dump(OMS_DumpInterface& dumpObj) const
{
  struct SessionDumpInfo 
  {
    OMS_Session*          m_this;
    ClassID                         m_callbackInterfaceGuid;
    OmsCallbackInterface*     m_callbackInterface;
    IliveCacheSink*           m_lcSink;
    bool*                     m_critical_section_in_use;
    OMS_ISessionLockObjects* m_lockObjects;
    OMS_Context*          m_context;
    OMS_Context*          m_defaultContext;
    tsp00_Int4                m_timeout;
    tsp00_Int2                m_refCnt;
    tsp00_Int2                m_subtrans_lvl;
    bool                      m_stream_io;
    bool                      m_read_only;
    tsp00_Int2                m_filler1;
    tsp00_Int4                m_filler2;
  } sessionDumpInfo;
  sessionDumpInfo.m_this                     = CONST_CAST(OMS_Session*, this);
  sessionDumpInfo.m_callbackInterfaceGuid    = m_callbackInterfaceGuid;
  sessionDumpInfo.m_callbackInterface        = m_callbackInterface; 
  sessionDumpInfo.m_lcSink                   = m_lcSink;
  sessionDumpInfo.m_critical_section_in_use  = m_critical_section_in_use;
  sessionDumpInfo.m_lockObjects              = m_lockObjects;
  sessionDumpInfo.m_context                  = m_context;
  sessionDumpInfo.m_defaultContext           = m_defaultContext;
  sessionDumpInfo.m_timeout                  = m_timeout;
  sessionDumpInfo.m_refCnt                   = m_refCnt;
  sessionDumpInfo.m_subtrans_lvl             = m_subtrans_lvl;
  sessionDumpInfo.m_stream_io                = m_stream_io;
  sessionDumpInfo.m_read_only                = m_read_only;
  dumpObj.SetDumpLabel(LABEL_OMS_SESSION);
  dumpObj.Dump(&sessionDumpInfo, sizeof(sessionDumpInfo));
  m_context->Dump(dumpObj);
  m_beforeImages.Dump(dumpObj);
  dumpObj.SetDumpLabel(LABEL_OMS_BOUND_VERSION);
  OMS_Session* self = CONST_CAST(OMS_Session*, this);
  for (cgg251dclIterator<OMS_Context*,OMS_Session> iter = self->m_versionsBoundToTrans.begin();
    iter; ++iter)
  {
    struct ListDumpInfo 
    {
      void*            m_thisPtr;
      void*            m_nextPtr;
      void*            m_prevPtr;
      OMS_Context* m_context;
    } listDumpInfo;
    
    iter.Dump(listDumpInfo.m_thisPtr, listDumpInfo.m_nextPtr, listDumpInfo.m_prevPtr); 
    listDumpInfo.m_context = *iter();
    dumpObj.Dump(&listDumpInfo, sizeof(listDumpInfo));
  }
}

/*----------------------------------------------------------------------*/

bool OMS_Session::GetMethodCallMonitorInfo (OmsMonitorData& info) const
{
  if (m_inMethodCallEpilog)
  {
    m_monitor.GetCallStatistics(info);
    const bool AllocatorOnly = true;
    OMS_HResult hr = m_lcSink->EvalCallStatistics(!AllocatorOnly, info);
    SAPDB_MemCopyNoCheck(&info.m_methodName[0], &m_monitor_curr->cmiMethodName_gg00[0], sizeof(info.m_methodName));
    return true;
  }
  return false;
}

/*----------------------------------------------------------------------*/

bool OMS_Session::HistoryInUse(const OmsObjectId& oid)
{
  tgg00_BasisError         LCError;
  bool                     isUsed = true;
  OMS_UnknownContainerId UnknownFileId;    
  OMS_HResult hr = m_lcSink->IsObjHistoryUsed(*REINTERPRET_CAST(const OmsTypeOid*, &oid), isUsed, LCError);
  if (0 != LCError) {
    this->ThrowDBError(LCError, "OMS_Session::HistoryInUse", oid, __MY_FILE__, __LINE__);
  }
  return isUsed;
}

/*----------------------------------------------------------------------*/

/// Tries to lock all objects which are enumerated by the iterator 
/*!
** This method tries to lock all objects whose oid is enumerated by the iterator pOids. 
** If some of these objects are out-of-date, then the corresponding oids are appended
** to the iterator pErrOids. If more objects are out-of-date than the iterator can contain,
** then an exception OmsOutOfDate is thrown and the already aquired locks of all objects, 
** which are not stored in the local oms-cache, are freed.
** The timeout specified, is used for the complete routine. If a timeout occurs, then the
** exception e_request_timeout is thrown.
**
** \param oids [in] Iterator which enumerates all objects for which a lock shoud be aquired.
** \param timeout [in/out] In-parameter: the maximal execution time in sec for getting all the locks.
**                            If timeout==0, then it will not be waited for locks to be freed and
**                            objects, for which locks can not be aquired because of another already
**                            existing lock, will be append to the error-iterator, too.
**                         Out-parameter: the execution time in sec needed by the routine
** \param errOids [out] Iterator which enumerates all objects for which no lock could be
**                      aquired because they have been deleted.
** \param newConsistentView [in] If true: Special handling as the mass-lock is called from newConsistentView:
**                                 * if an error occurs all aquired locks will be released
**                                 * the kernel does not check against OutOfDate because of an update of 
**                                   an object. This is used when a new consistent view is created. 
**                                   Nevertheless the kernel might return an OutOfDate in this case 
**                                   which then means, that the object has been deleted. 
**
** \since 7.4.4 (PTS 1121449)
*/
00571 void OMS_Session::LockObjMass (OmsIOidReadIterator &oids, 
                               short               &timeout, 
                               OmsIOidAppender     &errOids,
                               bool                 newConsistentView)
{
  const char * msg = "OMS_Session::LockObjMass ";

  int              overallCnt    = 0;
  int              cnt           = 0;
  int              errCnt        = 0;
  tsp00_Int8       remainingTime = timeout * 1000000;
  tgg00_BasisError currError     = e_ok;
  OmsObjectId     *pCurrOid      = NULL;
  OmsObjectContainer *pObj       = NULL;

  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId           pOid           [OMS_MASS_OPERATION_CNT];
  char                    pOid_u         [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId            *pOid = reinterpret_cast<OmsObjectId*>(&pOid_u[0]);
  tgg91_PageRef           pObjVers       [OMS_MASS_OPERATION_CNT];
  tgg00_FileId           *ppContainerId  [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OMS_UnknownContainerId  pContainerId [OMS_MASS_OPERATION_CNT];
  char                    pContainerId_u[OMS_MASS_OPERATION_CNT * sizeof(OMS_UnknownContainerId)];
  OMS_UnknownContainerId *pContainerId = reinterpret_cast<OMS_UnknownContainerId*>(&pContainerId_u[0]);
  tgg00_BasisError        pDBError       [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer     *ppObj          [OMS_MASS_OPERATION_CNT];

  // Try to get a lock for all objects which are requested
  while (bool(oids)) {
    while (bool(oids) && cnt < OMS_MASS_OPERATION_CNT) {
      pCurrOid = CONST_CAST(OmsObjectId*, &(oids.omsGet()));

      // Remember entries for locking
      pOid[cnt] = *pCurrOid;
      if (newConsistentView){
        // The special setting of pObjVers signals the kernel that no check for 
        // OutOfDate, caused by an update, should be performed. If an OutOfDate
        // is returned, then the corresponding object has been deleted.
        pObjVers     [cnt].gg91SetDummyRef(); 
        new(&pContainerId [cnt]) OMS_UnknownContainerId();
        ppContainerId[cnt] = &pContainerId[cnt];
        ppObj        [cnt] = NULL;
        ++cnt;
      }
      else {
        pObj = m_context->FindObjInContext(pCurrOid);
        if (pObj && pObj->LockedFlag()){
          // Object is stored in the local cache and is already locked
          // => nothing must be done
        }
        else if (pObj){
          // Object is stored in the cache but not locked
          pObjVers     [cnt] = pObj->m_objseq;
          ppContainerId[cnt] = &pObj->m_containerInfo->GetFileId();
          ppObj        [cnt] = pObj;
          ++cnt;
        }
        else {
          // Object is not stored and must be dereferenced 
          // TODO: Should be later replaced by a mass deref with lock
          try {
            pObj = m_context->GetObj(*pCurrOid, true);
          }
          catch (DbpError &e){
            if (   e.m_errorNo == e_object_dirty
               || !newConsistentView && (  e.m_errorNo == e_object_not_found
                                       ||  e.m_errorNo == e_lock_collision
                                       || (e.m_errorNo == e_request_timeout && timeout == 0))){
              if (e.m_errorNo == e_object_dirty)
                IncOutOfDate();

              // Try to append outdated object to error structure
              if (!errOids.omsAppend(*pCurrOid)) {
                // Too many object have already been appended. Therefore release locks, which has already  
                // been aquired, and stop further processing

                if (newConsistentView){
                  // Release locks which have been aquired already
                  ReleaseLocks(oids, overallCnt);
                }

                if (e.m_errorNo == e_object_dirty)
                  throw OmsOutOfDate(*pCurrOid, __MY_FILE__, __LINE__);
                else
                  throw;
              }
              else {
                DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
                if (pCBInterface){
                  pCBInterface->dbpCaughtError(e);
                }       
              }
            }
            else {
              throw;
            }
          }
          if (pObj){
            pObj->MarkLocked();
          }
        }
      }
      ++oids;
      ++overallCnt;
    }


    if (cnt > 0) {
      // Mass lock
      OMS_HResult hr = m_lcSink->LockObjMass(
        cnt, &CurrentContext()->m_consistentView, ppContainerId, pOid, 
        pObjVers, remainingTime, errCnt, pDBError);

      for (int i=0; i<cnt; ++i){
        if (   pDBError[i] == e_object_dirty
            || !newConsistentView && (  pDBError[i] == e_object_not_found
                                    ||  pDBError[i] == e_lock_collision
                                    || (pDBError[i] == e_request_timeout && timeout == 0))){
          if (pDBError[i] == e_object_dirty)
            IncOutOfDate();

          // Try to append outdated object to error structure
          if (!errOids.omsAppend(pOid[i])) {
            // Too many object have already been appended. Therefore release locks, which has already  
            // been aquired, and stop further processing

            if (newConsistentView){
              // Release locks which have been aquired already
              ReleaseLocks(oids, overallCnt);
            }

            if (pDBError[i] == e_object_dirty)
              throw OmsOutOfDate(pOid[i], __MY_FILE__, __LINE__);
            else
              ThrowDBError(pDBError[i], msg, pOid[i], __MY_FILE__, __LINE__);
          }
          else {
            // Object has been appended to the error-list
            pDBError[i] = e_ok;
            --errCnt;
          }
        }
        else if (pDBError[i] != e_ok){
          if (newConsistentView){
            // Release locks which have been aquired already
            ReleaseLocks(oids, overallCnt);
          }

          // Unacceptable error occured
          ThrowDBError(pDBError[i], msg, pOid[i], __MY_FILE__, __LINE__);
        }
        else if (ppObj[i] != NULL){
          // Mark object as locked in the liboms
          ppObj[i]->MarkLocked();
        }
      }
      cnt = 0;

      // Check whether timeout has occured
      if (timeout > 0 && remainingTime < 0) {
        if (newConsistentView){
          // Release locks which have been aquired already
          ReleaseLocks(oids, overallCnt);
        }

        ThrowDBError(e_request_timeout, msg, __MY_FILE__, __LINE__);
      }

      // Check that all errors have been handled   PTS 1123704
      if (errCnt > 0){  
        ThrowDBError(e_unknown_error, msg, __MY_FILE__, __LINE__);
      }
    }
  }

  if (timeout > 0){
    // Return the execution time
    timeout -= (short) (remainingTime / 1000000);
  }
}

/*----------------------------------------------------------------------*/

int OMS_Session::MassDeref(OmsIDerefIter &derefIter)
{
  const char* msg = "OMS_Session::MassDeref ";

  int errCnt = 0;

  // Arrays for mass deref
  int noOfObj   = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId             pOid          [OMS_MASS_OPERATION_CNT];
  char                      pOid_u        [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId              *pOid = reinterpret_cast<OmsObjectId*>(&pOid_u[0]);
  tgg91_PageRef             pObjVers      [OMS_MASS_OPERATION_CNT];
  OMS_GuidEntry            *ppClassInfo   [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OMS_UnknownContainerId  pContainerId  [OMS_MASS_OPERATION_CNT];
  char                      pContainerId_u[OMS_MASS_OPERATION_CNT * sizeof(OMS_UnknownContainerId)];
  OMS_UnknownContainerId   *pContainerId = reinterpret_cast<OMS_UnknownContainerId*>(&pContainerId_u[0]);

  // arrays for mass deref of base class oids
  int noOfObjBC = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId             pOidBC        [OMS_MASS_OPERATION_CNT];
  char                      pOidBC_u      [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId              *pOidBC = reinterpret_cast<OmsObjectId*>(&pOidBC_u[0]);
  tgg91_PageRef             pObjVersBC    [OMS_MASS_OPERATION_CNT];
  OMS_GuidEntry            *ppClassInfoBC [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OMS_UnknownContainerId  pContainerIdBC[OMS_MASS_OPERATION_CNT];
  char                      pContainerIdBC_u[OMS_MASS_OPERATION_CNT * sizeof(OMS_UnknownContainerId)];
  OMS_UnknownContainerId   *pContainerIdBC = reinterpret_cast<OMS_UnknownContainerId*>(&pContainerIdBC_u[0]);

  // arrays used by both methods (exporting parameters of kernel call)
  OmsAbstractObject        *ppObj         [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer       *ppObjContainer[OMS_MASS_OPERATION_CNT];
  int                       pObjSize      [OMS_MASS_OPERATION_CNT];
  tgg00_BasisError          pDBError      [OMS_MASS_OPERATION_CNT];

  // Arrays to remember information over mass-deref call
  const OmsAbstractObject **pppAddr       [OMS_MASS_OPERATION_CNT];
  const OmsAbstractObject **pppAddrBC     [OMS_MASS_OPERATION_CNT];
  long                     *ppErrAddr     [OMS_MASS_OPERATION_CNT];
  long                     *ppErrAddrBC   [OMS_MASS_OPERATION_CNT];

  OMS_GuidEntry *pClassInfo = NULL;
#ifdef      LIVECACHE_INTGUIDS
  ClassID guid = -1;
#else
  ClassID guid = {0,0,0,{0,0,0,0,0,0,0,0}};
#endif

  int DBErrorCnt = 0;
  while (bool(derefIter)){
    // Read packages of maximal size OMS_MASS_OPERATION_CNT from the kernel
    while (noOfObj<OMS_MASS_OPERATION_CNT && noOfObjBC<OMS_MASS_OPERATION_CNT && bool(derefIter)) {
      OmsObjectId               oid      = derefIter.omsGetOid();
      const OmsAbstractObject **ppAddr   = derefIter.omsGetObjAddr();
      long                     *pErrAddr = derefIter.omsGetErrAddr();
      
      // Check whether object is already stored in the local oms-cache
      IncDeref();
      OmsObjectContainer* found = m_context->FindObjInContext(&oid);
      if (found) {
        if (found->DeletedFlag()){
          // Object is already marked as deleted in the local cache
          derefIter.omsSetResult(ppAddr, oid, NULL, pErrAddr, e_object_not_found);
        }
        else {
          // Append object to the return structure
          derefIter.omsSetResult(ppAddr, oid, 
                                 const_cast<const OmsAbstractObject*>(&found->m_pobj), 
                                 pErrAddr, e_ok);
        }  
      }
      else {
        // Buffer last classInfo to prevent unnecessary accesses to the class-hash
        if (pClassInfo == NULL || derefIter.omsGetGuid() != guid){
          guid        = derefIter.omsGetGuid();
          pClassInfo  = GetClassInfo(guid);
        } 

        if (pClassInfo->IsBaseClass()) {
          // oid may identifiy an object of a derived class, i.e. size is unknown.
          // Therefore first get container (and thereby the size) from the kernel and
          // then deref objects with known size.
          pOidBC[noOfObjBC]    = oid;
          new(&pContainerIdBC[noOfObjBC]) OMS_UnknownContainerId();
          pObjVersBC[noOfObjBC].gg91SetNilRef();
          pppAddrBC[noOfObjBC] = ppAddr;
          ppErrAddrBC[noOfObjBC] = pErrAddr;
          ++noOfObjBC;
        }
        else {
          pOid[noOfObj]        = oid;
          ppClassInfo[noOfObj] = pClassInfo;
          new(&pContainerId[noOfObj]) OMS_UnknownContainerId();
          pObjVers[noOfObj].gg91SetNilRef();
          pppAddr[noOfObj]     = ppAddr;
          ppErrAddr[noOfObj]   = pErrAddr;
          ++noOfObj;
        }
      }
      ++derefIter;
    }


    if (noOfObj == OMS_MASS_OPERATION_CNT || (noOfObj > 0 && !bool(derefIter))) {
      // mass deref of objects which are not already stored in the local oms-cache
      int errorCnt = m_context->LoadObjsFromLiveCacheBase(noOfObj, pOid, pObjVers, false, 
                       ppObjContainer, pDBError, ppObj, ppClassInfo, pContainerId, pObjSize);
      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObj; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddr[i], pOid[i], 
                               const_cast<const OmsAbstractObject*>(&ppObjContainer[i]->m_pobj), 
                               ppErrAddr[i], pDBError[i]);
      }
      noOfObj = 0;
    }

    if (noOfObjBC == OMS_MASS_OPERATION_CNT || (noOfObjBC > 0 && !bool(derefIter))) {
      // Mass-Deref from the kernel of objects which belong to a base class
      int errorCnt = m_context->LoadBaseClsObjsFromLiveCacheBase(noOfObjBC, pOidBC, pObjVersBC, false,
                       ppObjContainer, pDBError, ppObj, ppClassInfoBC, pContainerIdBC, pObjSize);
      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObjBC; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddrBC[i], pOidBC[i], 
                      const_cast<const OmsAbstractObject*>(&ppObjContainer[i]->m_pobj), 
                      ppErrAddrBC[i], pDBError[i]);
      }
      noOfObjBC = 0;
    }
  }

  return DBErrorCnt;
}

/*----------------------------------------------------------------------*/

int OMS_Session::MassDerefForUpd(OmsIDerefIterForUpd &derefIter,
                                 bool                 doLock)
{
  const char* msg = "OMS_Session::MassDerefForUpd ";

  int errCnt = 0;

  // Arrays for mass deref
  int noOfObj   = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId           pOid          [OMS_MASS_OPERATION_CNT];
  char                    pOid_u        [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId            *pOid = reinterpret_cast<OmsObjectId*>(&pOid_u[0]);
  tgg91_PageRef           pObjVers      [OMS_MASS_OPERATION_CNT];
  OMS_GuidEntry          *ppClassInfo   [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OMS_UnknownContainerId  pContainerId  [OMS_MASS_OPERATION_CNT];
  char                    pContainerId_u[OMS_MASS_OPERATION_CNT * sizeof(OMS_UnknownContainerId)];
  OMS_UnknownContainerId *pContainerId = reinterpret_cast<OMS_UnknownContainerId*>(&pContainerId_u[0]);
  
  // arrays for mass deref of base class oids
  int noOfObjBC = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId             pOidBC        [OMS_MASS_OPERATION_CNT];
  char                      pOidBC_u      [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId              *pOidBC = reinterpret_cast<OmsObjectId*>(&pOidBC_u[0]);
  tgg91_PageRef             pObjVersBC    [OMS_MASS_OPERATION_CNT];
  OMS_GuidEntry            *ppClassInfoBC [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OMS_UnknownContainerId  pContainerIdBC[OMS_MASS_OPERATION_CNT];
  char                      pContainerIdBC_u[OMS_MASS_OPERATION_CNT * sizeof(OMS_UnknownContainerId)];
  OMS_UnknownContainerId   *pContainerIdBC = reinterpret_cast<OMS_UnknownContainerId*>(&pContainerIdBC_u[0]);

  // arrays for locking
  int lockCnt = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId           pLockOid           [OMS_MASS_OPERATION_CNT];
  char                    pLockOid_u         [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId            *pLockOid = reinterpret_cast<OmsObjectId*>(&pLockOid_u[0]);
  tgg91_PageRef           pLockObjVers       [OMS_MASS_OPERATION_CNT];
  tgg00_FileId           *ppLockContainerId  [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer     *ppLockContainerPtr [OMS_MASS_OPERATION_CNT];

  // arrays used by all methods (exporting parameters of kernel call)
  OmsAbstractObject      *ppObj         [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer     *ppObjContainer[OMS_MASS_OPERATION_CNT];
  int                     pObjSize      [OMS_MASS_OPERATION_CNT];
  tgg00_BasisError        pDBError      [OMS_MASS_OPERATION_CNT];

  // Arrays to remember information over mass-deref call
  OmsAbstractObject **pppAddr     [OMS_MASS_OPERATION_CNT];
  OmsAbstractObject **pppAddrBC   [OMS_MASS_OPERATION_CNT];
  long               *ppErrAddr   [OMS_MASS_OPERATION_CNT];
  long               *ppErrAddrBC [OMS_MASS_OPERATION_CNT];

  OMS_GuidEntry *pClassInfo = NULL;
#ifdef      LIVECACHE_INTGUIDS
  ClassID guid = -1;
#else
  ClassID guid = {0,0,0,{0,0,0,0,0,0,0,0}};
#endif

  int DBErrorCnt = 0;
  while (bool(derefIter)){
    // Read packages of maximal size OMS_MASS_OPERATION_CNT from the kernel
    while (noOfObj<OMS_MASS_OPERATION_CNT && noOfObjBC<OMS_MASS_OPERATION_CNT && bool(derefIter)) {
      OmsObjectId               oid      = derefIter.omsGetOid();
      OmsAbstractObject       **ppAddr   = derefIter.omsGetObjAddr();
      long                     *pErrAddr = derefIter.omsGetErrAddr();
      
      // Check whether object is already stored in the local oms-cache
      IncDeref();
      OmsObjectContainer* found = m_context->FindObjInContext(&oid);
      if (found) {
        if (found->DeletedFlag()){
          // Object is already marked as deleted in the local cache
          derefIter.omsSetResult(ppAddr, oid, NULL, pErrAddr, e_object_not_found);
        }
        else {
          // Object is found in the local cache
          if (doLock && !m_context->IsVersion() && !found->LockedFlag()){
            // remember necessary information for later mass lock
            pLockOid          [lockCnt] = oid;
            pLockObjVers      [lockCnt] = found->m_objseq;
            ppLockContainerId [lockCnt] = &found->GetContainerInfo(m_context)->GetFileId();
            ppLockContainerPtr[lockCnt] = found;
            ++lockCnt;
          }
          // Append object to the return structure
          derefIter.omsSetResult(ppAddr, oid, ForUpdPtr(found), pErrAddr, e_ok);
        }  
      }
      else {
        // Buffer last classInfo to prevent unnecessary accesses to the class-hash
        if (pClassInfo == NULL || derefIter.omsGetGuid() != guid){
          guid        = derefIter.omsGetGuid();
          pClassInfo  = GetClassInfo(guid);
        } 

        if (pClassInfo->IsBaseClass()) {
          // oid may identifiy an object of a derived class, i.e. size is unknown.
          // Therefore first get container (and thereby the size) from the kernel and
          // then deref objects with known size.
          pOidBC[noOfObjBC]      = oid;
          new(&pContainerIdBC[noOfObjBC]) OMS_UnknownContainerId();
          pObjVersBC[noOfObjBC].gg91SetNilRef();
          pppAddrBC[noOfObjBC]   = ppAddr;
          ppErrAddrBC[noOfObjBC] = pErrAddr;
          ++noOfObjBC;
        }
        else {
          pOid[noOfObj]        = oid;
          ppClassInfo[noOfObj] = pClassInfo;
          new(&pContainerId[noOfObj]) OMS_UnknownContainerId();
          pObjVers[noOfObj].gg91SetNilRef();
          pppAddr[noOfObj]     = ppAddr;
          ppErrAddrBC[noOfObj] = pErrAddr;
          ++noOfObj;
        }
      }
      ++derefIter;
    }


    if (noOfObj == OMS_MASS_OPERATION_CNT || (noOfObj > 0 && !bool(derefIter))) {
      // mass deref of objects which are not already stored in the local oms-cache
      int errorCnt = m_context->LoadObjsFromLiveCacheBase(noOfObj, pOid, pObjVers, doLock,
                       ppObjContainer, pDBError, ppObj, ppClassInfo, pContainerId, pObjSize);
      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObj; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddr[i], pOid[i], 
                               ppObjContainer[i] == NULL ? NULL : ForUpdPtr(ppObjContainer[i]), 
                               ppErrAddr[i], pDBError[i]);
      }
      noOfObj = 0;
    }

    if (noOfObjBC == OMS_MASS_OPERATION_CNT || (noOfObjBC > 0 && !bool(derefIter))) {
      // Mass-Deref from the kernel of objects which belong to a base class
      int errorCnt = m_context->LoadBaseClsObjsFromLiveCacheBase(noOfObjBC, pOidBC, pObjVersBC, doLock,
                       ppObjContainer, pDBError, ppObj, ppClassInfoBC, pContainerIdBC, pObjSize);
      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObjBC; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddrBC[i], pOidBC[i], 
                               ppObjContainer[i] == NULL ? NULL : ForUpdPtr(ppObjContainer[i]), 
                               ppErrAddrBC[i], pDBError[i]);
      }
      noOfObjBC = 0;
    }

    if (lockCnt == OMS_MASS_OPERATION_CNT || (lockCnt > 0 && !bool(derefIter))) {
      // Mass lock
      tsp00_Int8 timeout = 0;
      OMS_HResult hr = m_lcSink->LockObjMass( lockCnt, &m_context->m_consistentView, ppLockContainerId,
                         pLockOid, pLockObjVers, timeout, errCnt, pDBError);
      m_context->LockResult (lockCnt, pDBError, ppLockContainerPtr, pOid, msg); 
      lockCnt = 0;
    }
  }

  return DBErrorCnt;
}

/*----------------------------------------------------------------------*/
// PTS 1122194
int OMS_Session::MassDerefViaKey(OmsIDerefKeyIter &derefIter)
{
  const char* msg = "OMS_Session::MassDerefViaKey ";

  int errCnt = 0;

  // Arrays for mass deref
  int noOfObj   = 0;
  unsigned char            *ppBinaryKey   [OMS_MASS_OPERATION_CNT];
  int                       pKeyLen       [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId             pOid          [OMS_MASS_OPERATION_CNT];
  char                      pOid_u        [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId              *pOid = reinterpret_cast<OmsObjectId*>(&pOid_u[0]);
  tgg91_PageRef             pObjVers      [OMS_MASS_OPERATION_CNT];
  OMS_ClassIdEntry         *ppClsInfo     [OMS_MASS_OPERATION_CNT];
  tgg01_ContainerId         pContainerId  [OMS_MASS_OPERATION_CNT];

  // exporting parameters of kernel call
  OmsAbstractObject        *ppObj         [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer       *ppObjContainer[OMS_MASS_OPERATION_CNT];
  int                       pObjSize      [OMS_MASS_OPERATION_CNT];
  tgg00_BasisError          pDBError      [OMS_MASS_OPERATION_CNT];

  const OmsAbstractObject **pppAddr       [OMS_MASS_OPERATION_CNT];
  const unsigned char      *ppKey         [OMS_MASS_OPERATION_CNT];
  long                     *ppErrAddr     [OMS_MASS_OPERATION_CNT];

  int DBErrorCnt = 0;
  while (bool(derefIter)){
    // Read packages of maximal size OMS_MASS_OPERATION_CNT from the kernel
    while (noOfObj<OMS_MASS_OPERATION_CNT && bool(derefIter)) {
      IncDerefKey();

      // Remember original key and address where to store the result
      const OmsAbstractObject **ppAddr   = derefIter.omsGetObjAddr();
      const unsigned char      *pKey     = derefIter.omsGetKey();
      long                     *pErrAddr = derefIter.omsGetErrAddr();

      // Get container info
      OMS_ClassIdEntry*  pClsInfo = GetClsInfo(derefIter.omsGetGuid(), 
                                               derefIter.omsGetSchema(), 
                                               derefIter.omsGetContainerNo());

      // Convert key into binary representation
      OmsObjectContainer *pObj         = GetMemory(*pClsInfo);
      unsigned char      *pBinaryKey   = pClsInfo->GetKeyPtr(pObj);
      OmsAbstractObject  *pAbstractObj = &pObj->m_pobj;
      pAbstractObj->omsKeyToBinary(pKey, pBinaryKey);

      // Check whether object is already stored in the local oms-cache.
      // A key-access to the oms cache is possible if either objects are created
      // in a version, or the cached key feature is switched on.
      OmsObjectContainer* found = NULL;
      if (pClsInfo->UseCachedKeys() || m_context->IsVersion()){
        found = pClsInfo->VersionFindKey(pBinaryKey);
        if (found){
          // Statistics
          IncCacheHit(found->m_oid);

          // release memory
          pClsInfo->chainFree(*m_context, pObj, 22);

          if (found->DeletedFlag()) 
            derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(),
                                   NULL, pErrAddr, e_object_not_found);
          else 
            derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(),
                                   &found->m_pobj, pErrAddr, e_ok);
        }
        else if (pClsInfo->UseCachedKeys() && pClsInfo->IsCacheMiss(pBinaryKey)) {
          // Statistics
          IncCacheMiss();

          // release memory
          pClsInfo->chainFree(*m_context, pObj, 23);

          derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(), 
                                 NULL, pErrAddr, e_object_not_found);
        }
      }

      if (!found){
        // Remember data which is needed to store the result after the deref
        pppAddr     [noOfObj]        = ppAddr;
        ppKey       [noOfObj]        = pKey;
        ppErrAddr   [noOfObj]        = pErrAddr;

        // insert key into array for mass deref            
        ppBinaryKey [noOfObj]        = pBinaryKey;
        pObjVers    [noOfObj].gg91SetNilRef();
        ppClsInfo   [noOfObj]        = pClsInfo;
        pContainerId[noOfObj]        = pClsInfo->GetFileId(); 
        pKeyLen     [noOfObj]        = pClsInfo->GetKeyDesc().GetLen();
        pObjSize    [noOfObj]        = pClsInfo->GetObjectSize();

        // Get object frame to store the objects
        ppObjContainer[noOfObj]     = pObj;

        // Determine position where the kernel should write the object to. As the vtbl-pointer
        // is stored at the beginning of the abstract object the position must be incremented
        // by the size of a pointer.)
        ppObj[noOfObj] = (OmsAbstractObject*) ((unsigned char*) (&ppObjContainer[noOfObj]->m_pobj) + sizeof(void*));
        ++noOfObj;
      }

      ++derefIter;
    }

    if (noOfObj == OMS_MASS_OPERATION_CNT || (noOfObj > 0 && !bool(derefIter))) {
      // mass deref of objects which are not already stored in the local oms-cache
      int errorCnt = m_context->LoadObjsViaKeyFromLCBase(noOfObj, pKeyLen, ppBinaryKey, pOid, 
                        pObjVers, false, ppObjContainer, pDBError, ppObj, ppClsInfo, 
                        pContainerId, pObjSize);

      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObj; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddr[i], ppKey[i] , ppClsInfo[i]->GetKeyDesc().GetLen(), 
                               const_cast<const OmsAbstractObject*>(&ppObjContainer[i]->m_pobj), 
                               ppErrAddr[i], pDBError[i]);

        if (ppClsInfo[i]->UseCachedKeys() && ppObjContainer[i] != NULL){
          // Insert object into search structure for cached keys
          ppClsInfo[i]->VersionAddKey(ppObjContainer[i], m_context, true);
        }
      }
      noOfObj = 0;
    }
  }

  return DBErrorCnt;
}

/*----------------------------------------------------------------------*/
// PTS 1122194
int OMS_Session::MassDerefViaKeyForUpd(OmsIDerefKeyIterForUpd &derefIter, bool doLock)
{
  const char* msg = "OMS_Session::MassDerefViaKeyForUpd ";

  int errCnt = 0;

  // Arrays for mass deref
  int noOfObj   = 0;
  unsigned char            *ppBinaryKey   [OMS_MASS_OPERATION_CNT];
  int                       pKeyLen       [OMS_MASS_OPERATION_CNT];
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId             pOid          [OMS_MASS_OPERATION_CNT];
  char                      pOid_u        [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId              *pOid = reinterpret_cast<OmsObjectId*>(&pOid_u[0]);
  tgg91_PageRef             pObjVers      [OMS_MASS_OPERATION_CNT];
  OMS_ClassIdEntry         *ppClsInfo     [OMS_MASS_OPERATION_CNT];
  tgg01_ContainerId         pContainerId  [OMS_MASS_OPERATION_CNT];

  // arrays for locking
  int lockCnt = 0;
  // Prevent the calling of the constructor for every entry. An assignment is done in the loop.
  //OmsObjectId           pLockOid           [OMS_MASS_OPERATION_CNT];
  char                    pLockOid_u         [OMS_MASS_OPERATION_CNT * sizeof(OmsObjectId)];
  OmsObjectId            *pLockOid = reinterpret_cast<OmsObjectId*>(&pLockOid_u[0]);
  tgg91_PageRef           pLockObjVers       [OMS_MASS_OPERATION_CNT];
  tgg00_FileId           *ppLockContainerId  [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer     *ppLockContainerPtr [OMS_MASS_OPERATION_CNT];

  // exporting parameters of kernel call
  OmsAbstractObject        *ppObj         [OMS_MASS_OPERATION_CNT];
  OmsObjectContainer       *ppObjContainer[OMS_MASS_OPERATION_CNT];
  int                       pObjSize      [OMS_MASS_OPERATION_CNT];
  tgg00_BasisError          pDBError      [OMS_MASS_OPERATION_CNT];

  OmsAbstractObject       **pppAddr       [OMS_MASS_OPERATION_CNT];
  const unsigned char      *ppKey         [OMS_MASS_OPERATION_CNT];
  long                     *ppErrAddr     [OMS_MASS_OPERATION_CNT];

  int DBErrorCnt = 0;
  while (bool(derefIter)){
    // Read packages of maximal size OMS_MASS_OPERATION_CNT from the kernel
    while (noOfObj<OMS_MASS_OPERATION_CNT && bool(derefIter)) {
      IncDerefKey();

      // Remember original key and address where to store the result
      OmsAbstractObject   **ppAddr   = derefIter.omsGetObjAddr();
      const unsigned char  *pKey     = derefIter.omsGetKey();
      long                 *pErrAddr = derefIter.omsGetErrAddr();

      // Get container info
      OMS_ClassIdEntry*  pClsInfo = GetClsInfo(derefIter.omsGetGuid(), 
                                               derefIter.omsGetSchema(), 
                                               derefIter.omsGetContainerNo());

      // Convert key into binary representation
      OmsObjectContainer *pObj         = GetMemory(*pClsInfo);
      unsigned char      *pBinaryKey   = pClsInfo->GetKeyPtr(pObj);
      OmsAbstractObject  *pAbstractObj = &pObj->m_pobj;
      pAbstractObj->omsKeyToBinary(pKey, pBinaryKey);

      // Check whether object is already stored in the local oms-cache.
      // A key-access to the oms cache is possible if either objects are created
      // in a version, or the cached key feature is switched on.
      OmsObjectContainer* found = NULL;
      if (pClsInfo->UseCachedKeys() || m_context->IsVersion()){
        found = pClsInfo->VersionFindKey(pBinaryKey);
        if (found){
          // Statistics
          IncCacheHit(found->m_oid);

          // release memory
          pClsInfo->chainFree(*m_context, pObj, 24);

          if (found->DeletedFlag()) 
            // Object is stored in local cache, but marked as deleted
            derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(),
                                   NULL, pErrAddr, e_object_not_found);
          else {
            // Object is stored in the local cache
            if (doLock && !m_context->IsVersion() && !found->LockedFlag()){
              // remember necessary information for later mass lock
              pLockOid          [lockCnt] = found->m_oid;
              pLockObjVers      [lockCnt] = found->m_objseq;
              ppLockContainerId [lockCnt] = &pClsInfo->GetFileId();
              ppLockContainerPtr[lockCnt] = found;
              ++lockCnt;
            }

            derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(),
                                   ForUpdPtr(found), pErrAddr, e_ok);
          }
        }
        else if (pClsInfo->UseCachedKeys() && pClsInfo->IsCacheMiss(pBinaryKey)) {
          // Statistics
          IncCacheMiss();

          // release memory
          pClsInfo->chainFree(*m_context, pObj, 25);

          derefIter.omsSetResult(ppAddr, pKey, pClsInfo->GetKeyDesc().GetLen(), 
                                 NULL, pErrAddr, e_object_not_found);
        }
      }

      if (!found){
        // Remember data which is needed to store the result after the deref
        pppAddr     [noOfObj]        = ppAddr;
        ppKey       [noOfObj]        = pKey;
        ppErrAddr   [noOfObj]        = pErrAddr;

        // insert key into array for mass deref            
        ppBinaryKey [noOfObj]        = pBinaryKey;
        pObjVers    [noOfObj].gg91SetNilRef();
        ppClsInfo   [noOfObj]        = pClsInfo;
        pContainerId[noOfObj]        = pClsInfo->GetFileId(); 
        pKeyLen     [noOfObj]        = pClsInfo->GetKeyDesc().GetLen();
        pObjSize    [noOfObj]        = pClsInfo->GetObjectSize();

        // Get object frame to store the objects
        ppObjContainer[noOfObj]     = pObj;

        // Determine position where the kernel should write the object to. As the vtbl-pointer
        // is stored at the beginning of the abstract object the position must be incremented
        // by the size of a pointer.)
        ppObj[noOfObj] = (OmsAbstractObject*) ((unsigned char*) (&ppObjContainer[noOfObj]->m_pobj) + sizeof(void*));
        ++noOfObj;
      }

      ++derefIter;
    }

    if (lockCnt == OMS_MASS_OPERATION_CNT || (lockCnt > 0 && !bool(derefIter))) {
      // Mass lock
      tsp00_Int8 timeout = 0;
      OMS_HResult hr = m_lcSink->LockObjMass( lockCnt, &m_context->m_consistentView, ppLockContainerId,
                         pLockOid, pLockObjVers, timeout, errCnt, pDBError);
      m_context->LockResult (lockCnt, pDBError, ppLockContainerPtr, pOid, msg); 
      lockCnt = 0;
    }

    if (noOfObj == OMS_MASS_OPERATION_CNT || (noOfObj > 0 && !bool(derefIter))) {
      // mass deref of objects which are not already stored in the local oms-cache
      int errorCnt = m_context->LoadObjsViaKeyFromLCBase(noOfObj, pKeyLen, ppBinaryKey, pOid, 
                        pObjVers, doLock, ppObjContainer, pDBError, ppObj, ppClsInfo, 
                        pContainerId, pObjSize);

      DBErrorCnt += errorCnt;

      for (int i=0; i<noOfObj; ++i){
        // Append object, that have been read from the kernel, to the output
        derefIter.omsSetResult(pppAddr[i], ppKey[i] , ppClsInfo[i]->GetKeyDesc().GetLen(), 
                               ppObjContainer[i] == NULL ? NULL : ForUpdPtr(ppObjContainer[i]), 
                               ppErrAddr[i], pDBError[i]);

        if (ppClsInfo[i]->UseCachedKeys() && ppObjContainer[i] != NULL){
          // Insert object into search structure for cached keys
          ppClsInfo[i]->VersionAddKey(ppObjContainer[i], m_context, true);
        }
      }
      noOfObj = 0;
    }
  }

  return DBErrorCnt;
}

/*----------------------------------------------------------------------*/

/// Releases locks which have been aquired
/*!
** This method releases the first 'cnt' locks which are enumerated by the
** iterator 'pOid'. This functionality is used by LockObjMass in case of an error.
*/
01376 void OMS_Session::ReleaseLocks (OmsIOidReadIterator &oids, int cnt)
{
  oids.omsReset();
  for (int j = 0; j < cnt; ++j) {
    OmsObjectId* pCurrErrOid = CONST_CAST(OmsObjectId*, &(oids.omsGet()));
    try {
      if (!CurrentContext()->FindObjInContext(pCurrErrOid))
        UnlockObj(*pCurrErrOid);
    }
    catch (DbpError &e){
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }  
    }
    ++oids;
  }
}

/*----------------------------------------------------------------------*/
// PTS 1115027
// PTS 1121449
void OMS_Session::NewConsistentView (OmsIOidReadIterator& oids, short timeout, OmsIOidAppender& errOids)
{
  const char * msg = "OMS_Session::NewConsistentView ";

  // A version always keeps her initial consistent view as long as it exists
  if (CurrentContext()->IsVersion()) {
    return;
  }

  // Get locks on all objects for which there are before-images but which are not locked.
  // PTS 1128108
  CurrentContext()->LockObjWithBeforeImage();

  CurrentContext()->RemoveUnlockedObjFromCache();
 
  try {
    // Try to get a lock for each of the objects in pOid. timeout specifies the maximal time
    // for getting all locks. After the execution timeout contains the time needed to process
    // the call
    LockObjMass(oids, timeout, errOids, true);
  }
  catch (OmsLockTimeout&){ 
    // Write statistics
    MonitorWaitNewConsistentView((tsp00_Int4)(timeout));
    throw;
  }

  // Write statistics
  MonitorWaitNewConsistentView((tsp00_Int4)timeout); 
  
  // Register new consistent view in the kernel
  CurrentContext()->NewConsistentView();
}

/*----------------------------------------------------------------------*/

OmsAbstractObject* OMS_Session::NewKeyedObject(const ClassIDRef     guid, 
                                                   const unsigned char* key, 
                                                   OmsSchemaHandle      Schema, 
                                                   OmsContainerNo       ContainerNo)
{
  const char* msg = "OMS_Session::NewKeyedObject";
  const bool REUSE_FRAME = false;

  m_monitor.IncNewKeyedObject();

  bool        writeNewBeforeImage = true;
  bool        incNewObjectCnt     = true;

  HRESULT hr;
  OMS_ClassIdEntry*   pContainerInfo = this->GetClsInfo (guid, Schema, ContainerNo);
  OmsObjectContainer* po;
  if (m_context->IsVersion()) {
    po = this->GetMemoryInVersion(*pContainerInfo);
  } else {
    po = this->GetMemory(*pContainerInfo);
  }
  // transform key into binary representation
  unsigned char* pBinaryKey = pContainerInfo->GetKeyPtr(po);
  // introduce pAbstractObject, without this code call will not be virtual on some platforms
  OmsAbstractObject* pAbstractObject = &po->m_pobj;
  pAbstractObject->omsKeyToBinary(key, pBinaryKey);
  if (m_context->IsVersion()) {
    int                   ObjHistReadCount;
    OmsObjectContainerPtr found;
    found = pContainerInfo->VersionFindKey(pBinaryKey);
    bool keyInCache = (NULL != found);
    if (NULL != found && m_context->IsVersionOid(found->m_oid)) { // PTS 1117571
      if (!found->DeletedFlag()) {
        pContainerInfo->chainFree(*m_context, po, 26);
        throw OmsDuplicateKey (e_duplicate_hash_key, found->m_oid, __MY_FILE__, __LINE__);
      }
    }
    else {
      found = NULL;
      tsp00_Int2  DBError;
      hr = m_lcSink->GetObjWithKey (
        (unsigned char*) &m_context->m_consistentView,
        (unsigned char*) &pContainerInfo->GetFileId(),
        m_context->VersionContext(),
        pContainerInfo->GetKeyDesc().GetLen(), 
        (unsigned char*) pBinaryKey, 
        false, pContainerInfo->GetPersistentSize(), ((unsigned char*) &po->m_pobj) + sizeof(void*),
        REINTERPRET_CAST(OmsTypeOid*, &po->m_oid), (unsigned char*) &po->m_objseq, &ObjHistReadCount, &DBError);
      if FAILED (hr) {
        pContainerInfo->chainFree(*m_context, po, 27);
      }
      if ( DBError != 0 ) {
        if ( e_hash_key_not_found != DBError ) {
          pContainerInfo->chainFree(*m_context, po, 28);
          this->ThrowDBError (DBError, msg, __MY_FILE__, __LINE__);
        }
      }
      else {
        this->IncLogHop(ObjHistReadCount);
        OmsObjectContainerPtr found = m_context->FindObjInContext(&po->m_oid, true /*ignoreGeneration*/);  // PTS 1125361
        if (found) {
          if (!found->DeletedFlag()) {
            pContainerInfo->chainFree(*m_context, po, 29);
            throw OmsDuplicateKey (e_duplicate_hash_key, found->m_oid, __MY_FILE__, __LINE__);
          }
        }
        else {
            OmsObjectId oid = po->m_oid;
            pContainerInfo->chainFree(*m_context, po, 30);
            throw OmsDuplicateKey (e_duplicate_hash_key, oid, __MY_FILE__, __LINE__);
        }
      }
    }
    po->m_oid = m_context->VersionNewOid();
    po->m_objseq.gg91SetNilRef();
    
    if (pContainerInfo->UseCachedKeys()) { 
        // Check if object is registerd as cache-miss and if so 
        // remove it from cache miss structure
        if (pContainerInfo->IsCacheMiss(pBinaryKey)) {
            pContainerInfo->DeleteCacheMiss(pBinaryKey, CurrentContext());
        }
    }
    
    if (keyInCache){
        // replace pointer to key 
        pContainerInfo->VersionReplaceOrAddKeyContainerPtr(po, m_context);
    }
    else{
        // Always add entry to cached key structure, because this object
        // is created in a version
        pContainerInfo->VersionAddKey(po, m_context); 
    }

    m_context->PutObjectIntoContext (po, pContainerInfo->GetContainerHandle());
  }

  else {  // no version
    // Create new object in kernel
    tsp00_Int2  DBError1;
    HRESULT hr = m_lcSink->NewObj (
      (unsigned char*) &m_context->m_consistentView,
      (unsigned char*) &pContainerInfo->GetFileId(),
      m_context->VersionContext(),
      pContainerInfo->GetKeyDesc().GetPos(), 
      pContainerInfo->GetKeyDesc().GetLen(), 
      (unsigned char*) pBinaryKey,
      REINTERPRET_CAST(OmsTypeOid*, &po->m_oid), 
      (unsigned char*) &po->m_objseq,
      &DBError1);

    if (0 == DBError1) {
      if (pContainerInfo->UseCachedKeys()) {
        // Check whether object exists already in the context.
        // This might be possible in the following scenario
        // Tr 1:  Create(a) Commit         Delete(a) Commit
        // Tr 2:                   Read(a)                  Create(a)
        OmsObjectContainerPtr found = pContainerInfo->VersionFindKey(pBinaryKey);
        if (found) {
          //m_context->DeleteObjInContext(found, pContainerInfo);
          pContainerInfo->VersionDelKey(found, m_context);
        }

        // Check if object is registerd as cache-miss and if so 
        // remove it from cache miss structure
        if (pContainerInfo->IsCacheMiss(pBinaryKey)) {
          pContainerInfo->DeleteCacheMiss(pBinaryKey, CurrentContext());
        }
        
        // Insert object into cached key structure
        pContainerInfo->VersionAddKey(po, m_context);  
      }

      m_context->PutObjectIntoContext (po, pContainerInfo->GetContainerHandle());
    }

    else if (e_duplicate_hash_key == DBError1 ) {
      // Check, if current transcation has already deleted object.
      int        dummy;
      tsp00_Int2  DBError2;
      hr = m_lcSink->GetObjWithKey (
        (unsigned char*) &m_context->m_consistentView,
        (unsigned char*) &pContainerInfo->GetFileId(),
        m_context->VersionContext(),
        pContainerInfo->GetKeyDesc().GetLen(), 
        CONST_CAST(unsigned char*, pBinaryKey), 
        false,
        pContainerInfo->GetPersistentSize(), 
        ((unsigned char*) &po->m_pobj) + sizeof(void*),
        REINTERPRET_CAST(OmsTypeOid*, &po->m_oid),
        (unsigned char*) &po->m_objseq,
        &dummy,
        &DBError2);

      if (0 == DBError2) {
        // Get pointer to locally stored object
        OmsObjectContainer* found  = m_context->FindObjInContext(&po->m_oid, true /*ignoreGeneration*/);  // PTS 1125361
        if (found) {
           if (found->DeletedFlag()) {
             if (REUSE_FRAME) {
               // Reuse the same frame for the new object. This means, that the oid
               // of the new object is the same as the oid of the deleted object
               pContainerInfo->chainFree(*m_context, po, 31);

               if (found->IsNewObject()) {
                 // oid has already been counted as new
                 incNewObjectCnt = false;
               }

               // As the delete/new is mapped to an update in the kernel write a 
               // normal before image (NO NewBeforeImage)
               writeNewBeforeImage = false;
               InsertBeforeImage (found);

               // Assign pointer to reused frame and reset state info
               po = found;
               po->InitState(pContainerInfo);
   
             }
             else {  // NO REUSE_FRAME
               // Use a new frame for the new object although there is an object frame
               // of a deleted object. The generation counter of the oid of the new object 
               // will be changed, so that the oids are different.
               po->m_oid = found->m_oid;  
               ++po->m_oid;
               found->MarkReplaced();

               if (found->IsNewObject()) {
                 // oid has already been counted as new
                 incNewObjectCnt = false;
               }

               if (pContainerInfo->UseCachedKeys()) {
                 // Adapt pointer in Cached-Key tree.
                 // Check if object is registerd as cache-miss and if so 
                 // remove it from cache miss structure...
                 if (pContainerInfo->IsCacheMiss(pBinaryKey)) {
                   pContainerInfo->DeleteCacheMiss(pBinaryKey, CurrentContext());
                 }
                
                 // Replace or insert new object frame into cached key structure
                 pContainerInfo->VersionReplaceOrAddKeyContainerPtr(po, m_context);  
               }

               // Insert object into the oid-hash
               m_context->PutObjectIntoContext (po, pContainerInfo->GetContainerHandle());
             }
           }
           else {
             // Object does already exist, is stored in the cache and is not marked as deleted
             pContainerInfo->chainFree(*m_context, po, 32);
             throw OmsDuplicateKey(e_duplicate_hash_key, found->m_oid, __MY_FILE__, __LINE__);
             return NULL;
           }
        }  
        else {
          // Object does already exist in the kernel
          OmsObjectId oid = po->m_oid;
          pContainerInfo->chainFree(*m_context, po, 33);
          throw OmsDuplicateKey(e_duplicate_hash_key, oid, __MY_FILE__, __LINE__);
          return NULL;
        }
      }
      else if (e_hash_key_not_found == DBError2) {
        // 1.) Object is already created and committed by a concurrent running transaction,
        //     but because of the consistent view, this object is not visible by the own
        //     transaction.
        // 2.) Object was deleted by another transaction between the calls of 'NewObj' and 
        //     the 'GetObjWithKey' of this transaction. 
        //     As a 'e_hash_key_not_found' is not expected, when creating a new object,  
        //     this error is mapped to a e_duplicate_hash_key. 
        //     Trans 1: create(a,k) commit              del(a) commit
        //     Trans 2:                    |----------- NewKeyedObject(b,k) -----------|
        //                                  NewObj(b,k)              GetObjWithKey(k)
        //                                  dup_key                  not_found
        OmsObjectId oid = po->m_oid;
        pContainerInfo->chainFree(*m_context, po, 34);
        throw OmsDuplicateKey(e_duplicate_hash_key, oid, __MY_FILE__, __LINE__);
        return NULL;
      }
      else {
        // Unhandled error occured while executing GetObjWithKey
        OmsObjectId oid = po->m_oid;
        pContainerInfo->chainFree(*m_context, po, 35);
        char s[100]; 
        sp77sprintf(s, sizeof(s), "%s:%d", __MY_FILE__, __LINE__);
        ThrowDBError(DBError2, s, oid, __MY_FILE__, __LINE__);
        return NULL;
      }
    } 

    else if (e_key_still_visible == DBError1){
      // The object is existing in the current consistent view, but a concurrent running
      // transaction has deleted the object and this transaction is committed.  
      //  Trans 1: read(a)                 new(a)
      //  Trans 2:          del(a) commit
      OmsObjectId oid = po->m_oid;
      pContainerInfo->chainFree(*m_context, po, 36);
      throw OmsDuplicateKey(DBError1, oid, __MY_FILE__, __LINE__);
      return NULL;
    }

    else if (  /*e_request_timeout*/ 2600 == DBError1    // PTS 1124935
            || /*e_lock_collision*/  5000 == DBError1){  // PTS 1124935
      // The keyed object can not be created because another session has 
      // already created an object with the same key, but without having 
      // committed the creation.
      OmsObjectId oid = po->m_oid;
      pContainerInfo->chainFree(*m_context, po, 37);
        
      throw OmsKeyInUse(e_hash_key_in_use, oid, __MY_FILE__, __LINE__);
      return NULL;
    }

    else {
      // Unhandled error occured while executing NewObj
      pContainerInfo->chainFree(*m_context, po, 38);
      ThrowDBError(DBError1, msg, __MY_FILE__, __LINE__);
      return NULL;
    }
  }

  // Set flags in the object container
  po->MarkLocked();
  po->MarkStored();
  po->MarkAsNew();
  if (writeNewBeforeImage) {
    // A new object frame is used and therefore write a before image, which 
    // indicates, that on rollback, the object should be deleted
    InsertNewBeforeImage (po, pContainerInfo);
  }
  if (incNewObjectCnt) {
    // If an object with the same key has been created and deleted in the same
    // transaction before creating this object, then only the new object will
    // be flushed (resp. the old object frame is reused) and as the new-counter 
    // is already incremented for the old object a new increment is not needed.
    m_context->IncNewObjectsToFlush();
  }

  OMS_DETAIL_TRACE(omsTrNewObj, m_lcSink, "OMS_Session::NewKeyedObject : "
    << (incNewObjectCnt ? "to flush: " : "no flush: ")
    << po->m_oid << ", class: " << pContainerInfo->GetClassInfoPtr()->GetClassName());
  
  return &po->m_pobj;
}

/*----------------------------------------------------------------------*/

OmsAbstractObject* OMS_Session::NewObject(const ClassIDRef guid, OmsSchemaHandle Schema, OmsContainerNo ContainerNo)
{
  const char* msg = "OMS_Session::NewObject";

  this->AssertNotReadOnly(msg);

  m_monitor.IncNewObject();

  OMS_ClassIdEntry* pContainerInfo = this->GetClsInfo (guid, Schema, ContainerNo);
  OmsObjectContainerPtr po;
  if (m_context->IsVersion()) {
    po = this->GetMemoryInVersion(*pContainerInfo);
  } else {
    po  = this->GetMemory(*pContainerInfo);
  }
  if (this->InVersion()) {
    po->m_oid = m_context->VersionNewOid();
    po->m_objseq.gg91SetNilRef();
  }
  else {
    tsp00_Int2 DBError;
    OMS_HResult hr = m_lcSink->NewObj (
      (unsigned char*) &m_context->m_consistentView,
      (unsigned char*) &pContainerInfo->GetFileId(),
      m_context->VersionContext(),
      0,
      0,
      NULL,
      REINTERPRET_CAST(OmsTypeOid*, &po->m_oid), 
      (unsigned char*) &po->m_objseq,
      &DBError);
    if ( DBError != 0 ) {
      pContainerInfo->chainFree(*this->CurrentContext(), po, 39);
      this->ThrowDBError (DBError, msg, __MY_FILE__, __LINE__);
    }
  }
  m_context->PutObjectIntoContext (po, pContainerInfo->GetContainerHandle());
  po->MarkLocked();
  po->MarkStored();
  po->MarkAsNew();
  this->IncStore(); 
  this->InsertNewBeforeImage (po, pContainerInfo);
  OMS_DETAIL_TRACE(omsTrNewObj, m_lcSink, "OMS_Session::NewObject : to flush: "
    << po->m_oid << ", class: " << pContainerInfo->GetClassInfoPtr()->GetClassName());
  m_context->IncNewObjectsToFlush();

  return &po->m_pobj;
}

/*----------------------------------------------------------------------*/

const OmsVarOid& OMS_Session::NewVarObject(OmsSchemaHandle Schema, OmsContainerNo ContainerNo)
{
  const char* msg = "OMS_Session::NewVarObject";


  AssertNotReadOnly(msg);

  m_monitor.IncNewObject();

  OMS_ClassIdEntry* pContainerInfo = this->GetClsInfo (OMS_VAR_OBJ_GUID, Schema, ContainerNo);
  OmsObjectContainerPtr po  = this->GetMemory(*pContainerInfo);
  if (this->InVersion())
  {
    po->m_oid = m_context->VersionNewOid(); 
    po->m_objseq.gg91SetNilRef();
  }
  else {
    tgg00_BasisError DBError;
    OMS_HResult hr = m_lcSink->NewObj (
      (unsigned char*) &m_context->m_consistentView,
      (unsigned char*) &pContainerInfo->GetFileId(),
      m_context->VersionContext(),
      0, 0, NULL,
      REINTERPRET_CAST(OmsTypeOid*, &po->m_oid),
      (unsigned char*) &po->m_objseq,
      &DBError);
    if ( DBError != 0 ) {
      pContainerInfo->chainFree(*CurrentContext(), po, 40);
      this->ThrowDBError (DBError, msg, __MY_FILE__, __LINE__);
    }
  }
  m_context->PutObjectIntoContext (po, pContainerInfo->GetContainerHandle());
  po->MarkLocked();
  po->MarkVarObj();
  po->MarkAsNew();
  OMS_VarObjInfo* pObjInfo = new(&po->m_pobj) OMS_VarObjInfo(po->m_oid, 0, po->m_objseq);
  this->InsertNewBeforeImage (po, pContainerInfo);
  OMS_DETAIL_TRACE(omsTrNewObj, m_lcSink, "OMS_Session::NewVarObject : to flush: "
    << po->m_oid << ", class: " << pContainerInfo->GetClassInfoPtr()->GetClassName());
  m_context->IncNewObjectsToFlush();

  return *(REINTERPRET_CAST(OmsVarOid*, CONST_CAST(OmsObjectId*, &po->m_oid)));
}

/*----------------------------------------------------------------------*/

void OMS_Session::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)
{
  struct VirtualObject {
    void* vtptr;
  };  
  OMS_ClassIdEntry* pContainerInfo; 
  bool              isVarObject;
  bool              isRegistered = false;
  isVarObject = (0 == memcmp (&OMS_VAR_OBJ_GUID, &guid, sizeof(guid)));
  //try {  // PTS 1120873
    pContainerInfo = this->GetClsInfoForReg(guid, Schema, ContainerNo);
    isRegistered = (pContainerInfo != NULL);
  //}  // PTS 1120873
  //catch (DbpError& e) {
  //  if (e_unknown_guid != e.dbpError()) {
  //    throw e;
  //  }
  //}
  if (!isRegistered) {
    ObjectSize     += OmsObjectContainer::headerSize();
    PersistentSize -= /* virtual table ptr */ sizeof (void*);
    if  (isVarObject) {
      PersistentSize = sizeof(OMS_VarObjContainer);
    }
    OMS_ContainerInfo* p = omsRegisterContainer (m_lcSink, guid, ClassName, PersistentSize,
      ObjectSize, pBaseClass, 
      0, 0, false,   // key-description
      Schema, ContainerNo, (REINTERPRET_CAST(VirtualObject*, Obj))->vtptr, arrayByteSize); 
    pContainerInfo = new(m_context) OMS_ClassIdEntry (p, m_context);
    this->AddContainerInfo (pContainerInfo);
  }
  if (!isVarObject) {
    pContainerInfo->chainFree(*this->CurrentContext(), Obj, 41);
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::RegVarObjectContainer(OmsSchemaHandle Schema, OmsContainerNo cno)
{
  OMS_VarObjInfo info;
  RegContainer (Schema, OMS_VAR_OBJ_GUID, "VarObjContainer", sizeof(info), sizeof(info), NULL, &info, cno);  
}

/*----------------------------------------------------------------------*/

void OMS_Session::RegisterCallbackInterface(const ClassIDRef guid, OmsCallbackInterface* pInterface)
{
  if (NULL != m_callbackInterface) {
    if (m_callbackInterfaceGuid == guid) {
      return;
    }
    ReleaseCallbackInterface();
  }
  m_callbackInterface     = pInterface;
  m_callbackInterfaceGuid = guid;
}

/*----------------------------------------------------------------------*/

void OMS_Session::ReleaseVarObject(const OmsVarOid& oid)
{
  OmsObjectContainerPtr found = m_context->FindObjInContext (&oid);
  if (NULL != found) {
    OMS_VarObjInfo* pObjInfo = REINTERPRET_CAST (OMS_VarObjInfo*, &found->m_pobj);
    pObjInfo->unlock();
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::RemoveFromTransVersion(OMS_Context* context)
{
  for (cgg251dclIterator<OMS_Context*,OMS_Session> iter = m_versionsBoundToTrans.begin(); iter; ++iter) {
    if (*iter() == context) {
      m_versionsBoundToTrans.remove(iter);
      return;
    }
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::ReleaseCallbackInterface()
{
  // PTS 1128126
  // Ensure, that callback interface is set to null before calling 'omsDestroySelf'.
  OmsCallbackInterface *pInterface = m_callbackInterface;
  m_callbackInterface = NULL;
  if (NULL != pInterface) {
    try {
      pInterface->omsDestroySelf();
    } catch (DbpError &e) {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtError(e);
      }

      DbpBase(m_lcSink).dbpOpError("omsDestroySelf failed with error %d", e.dbpError());
      // make sure we don't have partially destroyed class as callback
      // this makes memory leaks possible
    } catch (BAD_ALLOC_GEO573&) {
      DbpErrorCallbackInterface *pCBInterface = DbpError::dbpGetCallback();  // PTS 1127871
      if (pCBInterface){
        pCBInterface->dbpCaughtBadAlloc();
      }

      DbpBase(m_lcSink).dbpOpError("omsDestroySelf failed with BAD_ALLOC");
      // make sure we don't have partially destroyed class as callback
      // this makes memory leaks possible
    } catch (...) {
      DbpBase(m_lcSink).dbpOpError("omsDestroySelf failed with unknown exception");
      // make sure we don't have partially destroyed class as callback
      // this makes memory leaks possible
    }
    //m_callbackInterface = NULL;
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::SetCurrentMonitorMethod(tgg01_COMMonitorInfo* p) 
{
  /* PTS 1107731 */
  tsp00_8ByteCounter heapUsed;
  m_lcSink->GetSessionHeapUsage(heapUsed);
  // start of procedure call
  m_heapAtMethodBegin = heapUsed;
  m_monitor_curr      = p;
  m_monitor.Reset();
}
 
/*----------------------------------------------------------------------*/

void OMS_Session::SetReadOnly(bool readOnly)
{
  if (readOnly && !m_allowReadOnly)
  {
    this->ThrowDBError (e_missing_privilege, "OMS_Session::SetReadOnly", __MY_FILE__, __LINE__);
  }
  m_read_only = readOnly;
}

/*----------------------------------------------------------------------*/

void OMS_Session::SetTimeout(short timeout)
{
  short       DummyError;
  tsp00_Int4  BufLen = sizeof(timeout);
  this->m_timeout = timeout;
  OMS_HResult hr = m_lcSink->MultiPurpose (m_set, mm_lock_timeout, &BufLen, 
    (unsigned char*) &timeout, &DummyError);
}

/*----------------------------------------------------------------------*/

void OMS_Session::ThrowDBError(tsp00_Int2 e, const char* msg, const OmsVersionId& v, const char *pFileName, int line)
{
    char resultMsg[256];
    int msgLen = (int) strlen(msg);
    if (msgLen < sizeof(resultMsg) - sizeof(v) - 2)
    {
        char* pChar = &resultMsg[0];
        SAPDB_MemCopyNoCheck(pChar, &msg[0], msgLen);
        pChar += msgLen;
        *pChar = ' ';
        ++pChar;
        SAPDB_MemCopyNoCheck (pChar, &v, sizeof(v));
        pChar += sizeof(v);
        *pChar = 0;
        this->ThrowDBError(e, &resultMsg[0], pFileName, line);
    }
    else
    {
        this->ThrowDBError(e, msg, pFileName, line);
    }
}
  
/*----------------------------------------------------------------------*/

void OMS_Session::ThrowDBError(tsp00_Int2 e, const char* msg, const char* pFileName, int line)
{
  this->ThrowDBError (e, msg, OmsObjectId(), pFileName, line);
}

/*----------------------------------------------------------------------*/

void OMS_Session::ThrowDBError(tsp00_Int2 e, const char* msg, const OmsObjectId& oid, const char* pFileName, int line)
{
  tsp00_Int4  BufLen = sizeof(e);
  tsp00_Int2  SqlError;
  // transform basis error into sql return code
  m_lcSink->MultiPurpose (m_change, mm_nil, &BufLen, 
    (unsigned char*) &e, &SqlError);
  if (omsDumpRequested(SqlError))
  {
    this->TriggerDump(SqlError); 
  }
  switch (SqlError) {
  case 400 :
  case 500 : /* PTS 1102829 */
    OMS_TRACE(omsTrError, m_lcSink, "throw LockTimeout");
    IncTimeout();
    throw OmsLockTimeout(oid, pFileName, line);
  default :
    OMS_TRACE(omsTrError, m_lcSink, "Error : " << e << "sqlError : " << SqlError << ", " << msg << ", " << oid);
    IncExceptions();
    throw DbpError (DbpError::DB_ERROR, SqlError, msg, oid, pFileName, line);
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::ThrowReturnCode (tsp00_Int2 e, const char* msg, const char* pFileName, unsigned int line)
{
  OMS_TRACE(omsTrError, m_lcSink, "SqlError : " << e << ", " << msg);
  OMS_Globals::Throw(DbpError (DbpError::DB_ERROR, e, msg, pFileName, line));
}

/*----------------------------------------------------------------------*/

void OMS_Session::Trace( const char*fmt, ... )
{
#if defined(WIN32)
  char buffer[256];
#else
  char buffer[1024];
#endif

  va_list args;
  va_start (args, fmt);
#if defined(WIN32)
  _vsnprintf ( buffer, sizeof(buffer), fmt, args );
#else
  vsprintf ( buffer, fmt, args );
  buffer[256] = '\0';
#endif
  m_lcSink->Vtrace ((tsp00_Int4) strlen(buffer), (unsigned char*) &buffer[0]);
  va_end (args);
}

/*----------------------------------------------------------------------*/

void OMS_Session::TransEnd()
{
  short DBError = 0;
  if (m_defaultContext->ExistsConsistentView()) {
    OMS_HResult hr = m_lcSink->EndConsistentView(
      (unsigned char*) &m_defaultContext->m_consistentView, &DBError);
  }
  m_currVarObjChunk.Clear();
  this->ClearFreeLists(4);
  this->ClearTransVersions();
  m_defaultContext->CleanContainerDir();

  m_defaultContext->ResetNewObjectsToFlush();
  m_isDataChanged = false;
  if ( 0 != DBError ) { 
    this->ThrowDBError (DBError, "omsTransEnd", __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

void OMS_Session::TriggerDump(tsp00_Int4 errorNo) 
{
  short DummyError;
  tsp00_Int4  BufLen = sizeof(errorNo);
  OMS_HResult hr = m_lcSink->MultiPurpose (m_outcopy, mm_nil, &BufLen, 
    (unsigned char*) &errorNo, &DummyError);
}

/*----------------------------------------------------------------------*/

void OMS_Session::UnlockObj (const OmsObjectId& oid)
{
  tsp00_Int2               DBError;
  OMS_UnknownContainerId UnknownFileId; 
  OMS_HResult hr = m_lcSink->UnlockObj ((unsigned char*) &UnknownFileId,
          REINTERPRET_CAST(OmsTypeOid*, CONST_CAST(OmsObjectId*, &oid)), &DBError);
  if ( DBError != 0 ) { 
    this->ThrowDBError (DBError, "OMS_Session::Unlock", oid, __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

bool OMS_Session::VersionBoundByMe(OMS_Context* context)
{
  for (cgg251dclIterator<OMS_Context*,OMS_Session> iter = m_versionsBoundToTrans.begin(); iter; ++iter) {
    if (*iter() == context) {
      return true;
    }
  }
  return false;
}

/*----------------------------------------------------------------------*/

void OMS_Session::Wait()
{
  tsp00_Bool ok;
  this->IncCntWaitOmsLockObj();
  tsp00_Int4 waitStart = OMS_Globals::GetKernelInterface()->Clock();
  m_lcSink->Wait(ok);
  this->IncWaitOmsLockObjSecs(OMS_Globals::GetKernelInterface()->Clock() - waitStart);
  if (!ok)
  {
    this->ThrowDBError(e_lock_collision, "OMS_Session::Wait", OmsObjectId(), __MY_FILE__, __LINE__);
  }
}

/*----------------------------------------------------------------------*/

OMS_Session::MethodCallEplilogScope::MethodCallEplilogScope(OMS_Session& session)
  : m_session(session)
{
  m_session.m_inMethodCallEpilog = true;
}

/*----------------------------------------------------------------------*/

OMS_Session::MethodCallEplilogScope::~MethodCallEplilogScope()
{
  m_session.m_inMethodCallEpilog = false;
}

Generated by  Doxygen 1.6.0   Back to index