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

void * SAPDBMem_RawAllocator::Allocate ( SAPDB_ULong  ByteCount  )  [virtual, inherited]

allocates ByteCount bytes from allocator

See also:
SAPDBMem_IRawAllocator::Allocate

Implements SAPDBMem_IRawAllocator.

Reimplemented in LVCMem_EmergencyAllocator.

Definition at line 1753 of file SAPDBMem_RawAllocator.cpp.

References SAPDBMem_RawAllocator::AlignedSize(), SAPDBMem_RawAllocator::AllocateResult(), SAPDBMem_RawAllocator::CheckFreeChunk(), SAPDBMem_RawAllocator::CChunk::ChunkAtOffset(), SAPDBMem_RawAllocator::CChunk::ChunkSize(), SAPDBMem_RawAllocator::THeapInfo::cntAlloc, SAPDBMem_RawAllocator::THeapInfo::extends, SAPDBMem_RawAllocator::CChunk::First(), SAPDBMem_RawAllocator::FrontLink(), SAPDBMem_RawAllocator::CFreeChunkLists::GetSmallFreeListIndex(), SAPDBMem_RawAllocator::Idx2BinBlock(), SAPDBMem_RawAllocator::IncrementUsed(), SAPDBMem_RawAllocator::IsSmallRequest(), SAPDBMem_RawAllocator::CChunk::Last(), SAPDBMem_RawAllocator::m_badAllocFunc, SAPDBMem_RawAllocator::m_binBlocks, SAPDBMem_RawAllocator::m_checkFlags, SAPDBMem_RawAllocator::m_freeLists, SAPDBMem_RawAllocator::m_heapInfo, SAPDBMem_RawAllocator::m_lock, SAPDBMem_RawAllocator::m_monitorCallStackLevel, SAPDBMem_RawAllocator::m_prev, SAPDBMem_RawAllocator::m_root, SAPDBMem_RawAllocator::m_supplement, SAPDBMem_RawAllocator::MallocExtend(), SAPDBMem_RawAllocator::CChunk::next, SAPDBMem_RawAllocator::CChunk::NextFreeList(), SAPDBMem_RawAllocator::CChunk::prev, SAPDBMem_RawAllocator::CChunk::PrevFreeList(), SAPDBMem_RawAllocator::RemoveFreeBigChunk(), SAPDBMem_RawAllocator::CChunk::SetHead(), SAPDBMem_RawAllocator::CChunk::SetHeadAndFoot(), SAPDBMem_RawAllocator::CChunk::SetInUseAtOffset(), and SAPDBMem_RawAllocator::CChunk::Unlink().

Referenced by RTEMem_Allocator::Allocate(), SAPDBMem_RawAllocator::Allocate(), SharedSQL_CommandCache::Allocate(), LVCMem_EmergencyAllocator::Allocate(), RTEMem_RteAllocator::Allocate(), LVCMem_Allocator::AllocateImplementation(), LVCMem_Allocator::BadAllocHandling(), DBProc_Handler::CalculateFunctionResult(), Join_AccessDesc::CreateKeys(), DBProc_Handler::ExecuteSqlStatement(), Join_JoinOperator2::GetNullRecord(), Join_JoinOperator::GetNullRecord(), GetResultDescription(), Join_AccessDesc::Join_AccessDesc(), Join_AccessOperator::Join_AccessOperator(), Join_JoinOperator::Join_JoinOperator(), Join_JoinOperator2::Join_JoinOperator2(), LVCMem_EmergencyAllocator::LVCMem_EmergencyAllocator(), LVCMem_Allocator::OmsAllocate(), SAPDBMem_RawAllocator::Reallocate(), SQLMan_SQLStatementContext::SQLMan_SQLStatementContext(), and DBProc_Debugger::storeExecuteInfo().

{
#ifdef SAPDBMem_USE_SYSTEM_ALLOC
  void *p = malloc(ByteCount);
  if (!p) 
    return (*m_badAllocFunc)(ByteCount);  
  return p;
#else
  int           monitorCallStackLevel = 0;
  CChunkPtr     victim;          /* inspected/selected chunk */
  CChunkPtr     remainder;       /* remainder of a chunk split */
  ChunkSize     victim_size;     /* its size */
  int           idx;             /* index for free list traversal */
  CChunkPtr     bin;             /* associated bin */
  ChunkSize     remainder_size;  /* its size */
  SAPDB_ULong   block;           /* block traverser bit */
  int           startidx;        /* first bin of a traversed block */
  int           extends = 0;
  CChunkPtr     q;               /* misc temp */
  bool          heapLocked = (0 == m_lock);
  
#if defined(RESERVE_PTR_SPACE)
  ByteCount += 2 * sizeof(void*);
#endif
#if defined(OSF1)
  ByteCount += sizeof(SAPDB_UInt4);     /* avoid cache line problems */
#else
  if (m_checkFlags & FL_NO_MANS_LAND)
  {
      ByteCount += sizeof(SAPDB_UInt4); /* reserve space for no man's land */
  }
#endif
  if (m_monitorCallStackLevel > 0)
  {
    monitorCallStackLevel = m_monitorCallStackLevel;
    ByteCount += sizeof(SAPDB_UInt4); /* reserve space for call back info */
  }
  ChunkSize nb = AlignedSize(ByteCount);
  ++m_heapInfo.cntAlloc;
  /* Check for exact match in a free list */
  do
  {
      if (IsSmallRequest(nb)) 
      {
          /* Faster version for small requests                           */
          /* No traversal or size check necessary for small free lists.  */
          idx = m_freeLists.GetSmallFreeListIndex(nb);
          q      = m_freeLists[idx];
          LOCK_HEAP(heapLocked);
          victim = q->Last();
          // check exact matching free list first 
          if (victim == q)
          {
              // Also scan the next one, since it would have a remainder < MINSIZE 
              q      = q->NextFreeList();
              victim = q->Last();
          }
          if (victim != q) 
          {
              // this free list satisfies the request
              if (!this->CheckFreeChunk(victim))
              {
                  continue;
              }
              victim_size   = victim->ChunkSize();
              this->IncrementUsed(victim_size);
              victim->Unlink(*this);
              victim->SetInUseAtOffset(victim_size);
              return AllocateResult(victim, monitorCallStackLevel);
          }
          idx += 2; /* Set for bin scan below. We've already scanned 2 free lists. */
try_again :
          if ( (block = Idx2BinBlock(idx)) <= m_binBlocks)  
          {
              
              /* Get to the first marked block */
              if ( (block & m_binBlocks) == 0) 
              {
                  /* force to an even block boundary */
                  idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH;
                  block <<= 1;
                  while ((block & m_binBlocks) == 0)
                  {
                      idx += BINBLOCKWIDTH;
                      block <<= 1;
                  }
              }
              
              /* For each possibly nonempty block ... */
              for (;;)  
              {
                  startidx = idx;          /* (track incomplete blocks) */
                  q = bin = m_freeLists[idx];
                  
                  /* For each bin in this block ... */
                  do
                  {
                      victim = bin->Last();
                      if (victim != bin)
                      {
                          if (!this->CheckFreeChunk(victim))
                          {
                              // the corrupted block has already been removed from free chain
                              goto try_again;
                          }
                          victim_size = victim->ChunkSize();
                          remainder_size = victim_size - nb;
                          if (remainder_size >= MINSIZE) /* split */
                          {
                              remainder = victim->ChunkAtOffset(nb);
                              victim->SetHead(nb | PREV_INUSE);
                              victim->Unlink(*this);
                              remainder->SetHeadAndFoot(remainder_size);
                              FrontLink(remainder, remainder_size);
                              this->IncrementUsed(nb);
                              return AllocateResult(victim, monitorCallStackLevel); 
                          }
                          else {
                              victim->SetInUseAtOffset(victim_size);
                              victim->Unlink(*this);
                              this->IncrementUsed(victim_size);
                              return AllocateResult(victim, monitorCallStackLevel);
                          }
                      }
                      bin = bin->NextFreeList();
                  }
                  while ((++idx & (BINBLOCKWIDTH - 1)) != 0);
                  
                  /* Clear out the block bit. */
                  
                  do   /* Possibly backtrack to try to clear a partial block */
                  {
                      if ((startidx & (BINBLOCKWIDTH - 1)) == 0)
                      {
                          m_binBlocks &= ~block;
                          break;
                      }
                      --startidx;
                      q = q->PrevFreeList();
                  } while (q->First() == q);
                  
                  /* Get to the next possibly nonempty block */
                  
                  if ( (block <<= 1) <= m_binBlocks && (block != 0) ) 
                  {
                      while ((block & m_binBlocks) == 0)
                      {
                          idx += BINBLOCKWIDTH;
                          block <<= 1;
                      }
                  }
                  else
                      break;
              }
          }
      }
      else
      {
          // large request
          LOCK_HEAP(heapLocked);
      }
      NodePtr pCurr           = m_root;
      NodePtr pLastGreater    = 0;
      size_t  lastVisitedSize = 0;
      // binary search for best fitting free list
      while (true)
      {
          if (0 == pCurr)
          {
              break;
          }
          victim_size = pCurr->m_size;       
          // search best free list
          if (victim_size < nb)
          {
              lastVisitedSize = victim_size;
              pCurr           = pCurr->m_right;
          }
          else
          {
              if (victim_size > nb)
              {
                  pLastGreater = pCurr;
                  pCurr        = pCurr->m_left;
              }
              else
              {
                  // exact match, remove and return oldest chunk from list
                  victim = pCurr->next;
                  this->RemoveFreeBigChunk(victim);
                  victim->SetInUseAtOffset(nb);
                  this->IncrementUsed(nb);
                  return AllocateResult(victim, monitorCallStackLevel);
              }
          }
      }
      if (0 != pLastGreater)
      { 
          // remove and return oldest chunk from list
          victim         = pLastGreater->next;
          victim_size    = victim->ChunkSize();
          remainder_size = victim_size - nb;
          if (!this->CheckFreeChunk (victim))
          {
              UNLOCK_HEAP;
              return (*m_badAllocFunc)(ByteCount);  
          }
          if (victim->next == victim->prev)
          {
              // list becomes empty
              if (remainder_size > lastVisitedSize)
              {
                  // node keeps position in tree, don't remove
                  if (remainder_size >= MAX_SMALLBIN_SIZE) /* split */
                  {
                      pLastGreater->m_size = remainder_size;
                      remainder            = victim->ChunkAtOffset(nb);
                      remainder->SetHeadAndFoot(remainder_size);
                      SET_MIN_FREE_BLOCK_PATTERN(remainder);
                      pLastGreater->next  = remainder;
                      pLastGreater->prev  = remainder;
                      remainder->next     = REINTERPRET_CAST(CChunkPtr, pLastGreater);
                      remainder->prev     = REINTERPRET_CAST(CChunkPtr, pLastGreater);
                      victim->SetHead(nb | PREV_INUSE);
                      /* TODO try to use end of free chunk -> no changes of pointers needed
                      victim->SetHead(remainder_size | (victim->size & SIZE_BITS));
                      victim = victim->ChunkAtOffset(remainder_size);
                      victim->SetHead(nb);
                      */
                      victim->SetInUseAtOffset(nb);
                      this->IncrementUsed(nb);
                      return AllocateResult(victim, monitorCallStackLevel);
                  }
              }
              this->RemoveFreeBigChunk(victim);
          }
          else
          {
              // remove from free list, list does not become empty
              victim->next->prev = victim->prev;
              victim->prev->next = victim->next;
          }
      }
      else
      {
          // no chunk found yet, try to use emergency list
          victim = 0;
          for (CChunkPtr pVictim = m_prev; pVictim != REINTERPRET_CAST(CChunkPtr, &m_root); pVictim = pVictim->prev)
          {
              if (pVictim->ChunkSize() >= nb)
              {
                  this->RemoveFreeBigChunk(victim);
                  victim         = pVictim;
                  victim_size    = victim->ChunkSize();
                  remainder_size = victim_size - nb;
                  break;
              }
          }
          if (0 == victim)
          {
              goto extend;
          }
      }
      if (remainder_size >= MINSIZE) /* split */
      {
          remainder = victim->ChunkAtOffset(nb);
          victim->SetHead(nb | PREV_INUSE);
          remainder->SetHeadAndFoot(remainder_size);
          FrontLink(remainder, remainder_size);
          this->IncrementUsed(nb);
          return AllocateResult(victim, monitorCallStackLevel); 
      }
      else {
          victim->SetInUseAtOffset(victim_size);
          this->IncrementUsed(victim_size);
          return AllocateResult(victim, monitorCallStackLevel);
      }
extend :
      /* Try to extend */
      if (
          ( 0 == extends ) && 
          ((m_supplement > 0) || (0 == m_heapInfo.extends)) 
          )
      {
          ++extends;
          if (MallocExtend(nb)) {
              continue;
          }
      }
      UNLOCK_HEAP;
      return (*m_badAllocFunc)(ByteCount);  
  }
  while(1);
#endif
}


Generated by  Doxygen 1.6.0   Back to index