Exemplo n.º 1
0
TEST(insert_many_ids_into_same_list, then_only_few_mallocs_must_be_called)
{
    int  i;
	int  expectedMallocCalls = 1000 / 36 + 1;
	uint expectedMemLen = AlignDefault(sizeof(SHashItem)) 
		                + AlignDefault(sizeof(int)) 
						+ AlignDefault(34);

	TEST_ASSERT_TRUE(fakeMemStorageCount > 0);
    TEST_ASSERT_EQUAL_UINT32(fakeMemStorageCount, expectedMallocCalls);

    for (i = 0; i < expectedMallocCalls; i++)
	{
	    TEST_ASSERT_EQUAL_UINT32(fakeMemStorage[i].memLen, expectedMemLen * 36);
	}
}
Exemplo n.º 2
0
/* This is an auxiliary function for allocateMemory method.
 * It allocates a whole new block, inserts it into 
 * the head of the set's block list 
 * and takes the whole memory from the entire block 
 * for a chunk.
 */
void* allocateChunkBlock(
    void*             self,
	size_t            chunkSize,
    MemoryContainer   container)
{
	IMemContainerManager _         = (IMemContainerManager)self;
	IErrorLogger         elog      = (IErrorLogger)_->errorLogger;
	size_t               blockSize = chunkSize + MEM_BLOCK_SIZE + MEM_CHUNK_SIZE;

	MemorySet	  set       = (MemorySet)container;
    MemoryBlock   block;
	MemoryChunk	  chunk;

    void*         chunkPtr;
    size_t        size      = AlignDefault(chunkSize);
    
    ASSERT(elog, funcMalloc != NULL, NULL);
    block = (MemoryBlock)funcMalloc(blockSize);

	/* Report malloc error */
	if (block == NULL)
	{
		showMemStat(_, topMemCont, 0);

		elog->log(LOG_ERROR, 
		          ERROR_CODE_OUT_OF_MEMORY, 
				  "Out of memory. Failed request size: %lu", 
				  chunkSize);
	}

	block->memset        = set;
	block->freeStart     = (char*)block + blockSize;
	block->freeEnd       = block->freeStart;

	chunk                = (MemoryChunk)((char*)block + MEM_BLOCK_SIZE);
	chunk->memsetorchunk = set;
	chunk->size          = size;
	chunk->sizeRequested = chunkSize;
    
	chunkPtr = MemoryChunkGetPointer(chunk);

	/* Insert the block into the head of 
	 * the set's block list.
	 */ 
	if (set->blockList != NULL)
	{
		block->next          = set->blockList->next;
		set->blockList->next = block;

		return chunkPtr;
	}
	
    block->next    = NULL;
	set->blockList = block;

	return chunkPtr;
}
Exemplo n.º 3
0
TEST(allocate_large_chunk, then_chunk_block_must_be_created)
{    
    int chunk_size_requested = size_alc;
    int chunk_size           = AlignDefault(chunk_size_requested);

	void*           chunkMem = mem_alc;
	MemoryChunk     chunk    = (MemoryChunk)((char*)chunkMem - MEM_CHUNK_SIZE); 

	TEST_ASSERT_NOT_NULL(chunkMem);
    TEST_ASSERT_NOT_NULL(chunk);

	TEST_ASSERT_EQUAL(chunk->memsetorchunk, mc_alc);
	TEST_ASSERT_EQUAL_INT32(chunk->size, chunk_size);
	TEST_ASSERT_EQUAL_INT32(chunk->sizeRequested, chunk_size_requested);
}
Exemplo n.º 4
0
void initializePage(
    void*         self,
    void*         page, 
    size_t        size, 
    size_t        suplSize)
{
    PageHeader        p = (PageHeader)page;

    suplSize = AlignDefault(suplSize);
    memset(p, 0, size);

    p->freeStart = SizeOfPageHeader;
    p->freeEnd   = size - suplSize;
    p->special   = size - suplSize;
}
Exemplo n.º 5
0
uint16 addItemToPage(
    void*          page,
    void*          item,
    size_t         size,
    uint16         itemnum,
    Bool           overwrite)
{
    ItemPointer         itemId;
    PageHeader     pageHdr     = (PageHeader)page;
    uint16         maxItemNum  = RowsCountOnPage(page) + 1;
    Bool           needShuffle = False;
    int            num;
    int            newFreeStart, newFreeEnd;
    size_t         alignedSize;

    if (IsItemIdValid(itemnum))
    {
        if (overwrite)
        {
            itemId = PageGetItemId(page, itemnum);

            /* If the item is in use or has not empty storage
             * we can not use it. Return 0.
             */
            if (ItemIdIsInUse(itemId) || ItemIdHasStorage(itemId))
                return 0;
        }
        else
        {
			/* If we are not overwriting an item
			 * and the offset number in less than max number
		     * Our page needs shuffle to free a room for the item.
		     */
            if (itemnum < maxItemNum)
                needShuffle = True;
        }
    }
    else
    {
        /* If itemnum is not passed in or is invalid,
         * we need to find a free item. If there does not exist
         * a free item, we will put it at the end of the page.
         */
        if (PageHasFreeItems(pageHdr))
        {
            /* Look for unused items */
            for (num = 1; num < maxItemNum; num++)
            {
                 itemId = PageGetItemId(page, itemnum);
    
                 /* If the item is unused we break. */
                 if (!ItemIdIsInUse(itemId) && !ItemIdHasStorage(itemId))
                     break;
            }

            /* If we have reached the maximum offset, there are not free items. */
            if (num >= maxItemNum)
            {
                 /* the hint is wrong, so reset it */
                 PageClearHasFreeLinePointers(page);
            }
        }
        else
        {
            /* If we have not a free item we try to insert it 
             * into the end of a page. 
             */
            itemnum = maxItemNum;
        }
    }

    /* If we are inserting an item into the end or with a shuffle
     * we need to insert an item into items array. We pull the free start
     * right on one position.
     */
    if (itemnum == maxItemNum || needShuffle)
        newFreeStart = pageHdr->freeStart + sizeof(ItemPointerData);
    else
        newFreeStart = pageHdr->freeStart;

    alignedSize = AlignDefault(size); 

    /* Calculate new free end. */
    newFreeEnd = (int)pageHdr->freeEnd - (int)alignedSize;

    /* if newFreeStart exceeds newFreeEnd we do not have 
     * a free room to put the item to
     */
    if (newFreeStart > newFreeEnd)
        return 0;

    itemId = PageGetItemId(page, itemnum);

    if (needShuffle)
        memmove(itemId + 1, itemId, 
            (maxItemNum - itemnum) * sizeof(ItemPointerData));

    itemId->flags = ITEM_NORMAL;
    itemId->off   = newFreeEnd;
    itemId->len   = size;

    /* copy the item's data onto the page */
    memcpy((char*)page + newFreeEnd, item, size);

    /* Change free space range, freeStart and freeEnd. */
    pageHdr->freeStart = (uint16)newFreeStart;
    pageHdr->freeEnd   = (uint16)newFreeEnd;

    return itemnum;
}
Exemplo n.º 6
0
/* Reallocate memory. When we need more memory
 * we allocate a piece of memory with an appropriate size,
 * copy an old memory and then free it.
 */
void* reallocateMemory(
    void*                  self,
	MemoryContainer        container, 
	void*                  old_mem, 
	size_t                 new_size)
{
	IMemContainerManager  _    = (IMemContainerManager)self;
	IErrorLogger          elog = _->errorLogger;
    
	MemorySet    set   = (MemorySet)container;
    MemoryChunk	 chunk = (MemoryChunk)((char*)old_mem - MEM_CHUNK_SIZE);  

	size_t		 oldsize = chunk->size;   
	void*        chunkPtr;
	void*        new_mem;

	/* Always return when a requested size is a decrease */
	if (oldsize >= new_size)
	    return old_mem;

	/* Check if for the chunk there was allocate a block */
	if (oldsize > set->chunkMaxSize)
	{
        /* Try to find the corresponding block first 
		 */
		MemoryBlock   block     = set->blockList;
        MemoryBlock   prevblock = NULL;

        size_t		  chunk_size;
		size_t		  block_size;
		char*         expected_block_end;

		while (block != NULL)
		{
            if (chunk == (MemoryChunk)((char*)block + MEM_BLOCK_SIZE))
				break;

			prevblock = block;
			block     = block->next;
		}

		/* Could not find the block. We should report an error. */
		if (block == NULL)
		{
			 elog->log(LOG_ERROR, 
		          ERROR_CODE_BLOCK_NOT_FOUND, 
				  "Could not find block containing chunk %p", 
				  chunk);

			 return NULL;
		}

        /* We should check that the chunk is only one 
		 * on the block.
		 */
		expected_block_end = (char*)block + 
			chunk->size +
            MEM_BLOCK_SIZE + 
			MEM_CHUNK_SIZE;

		ASSERT(elog, block->freeEnd == expected_block_end, NULL); 

		/* Do the realloc */
		chunk_size = AlignDefault(new_size);
		block_size = chunk_size + MEM_BLOCK_SIZE + MEM_CHUNK_SIZE;

		ASSERT(elog, funcRealloc != NULL, NULL); 
		block      = (MemoryBlock)funcRealloc(block, block_size);

		if (block == NULL)
		{
            showMemStat(_, topMemCont, 0);

	        elog->log(LOG_ERROR, 
		          ERROR_CODE_OUT_OF_MEMORY, 
				  "Out of memory. Failed request size: %lu", 
				  block_size);

		    return NULL;
		}

		block->freeStart = block->freeEnd = (char*)block + block_size;
        chunk = (MemoryChunk)((char*)block + MEM_BLOCK_SIZE);

		/* Change block pointer to newly allocated block. */
		if (prevblock == NULL)
			set->blockList = block;
		else
			prevblock->next = block;

		chunk->size = chunk_size;

		chunkPtr = MemoryChunkGetPointer(chunk);
	    return chunkPtr;
	}

	/* If we are here that this small block
	 * was taken from the free list. We allocate
	 * a new free chunk and the old chunk add to
	 * the free list. 
	 */
    new_mem = allocateMemory(_, container, new_size);

	/* copy existing memory to a new memory. */
	memcpy(new_mem, old_mem, oldsize);

	/* free old chunk */
	freeChunk(self, old_mem);
	return new_mem;
}
Exemplo n.º 7
0
/* Creates new memory set object. */
MemorySet memSetCreate(
    void*              self,
	MemoryContainer    container,
    MemoryContainer    parent,
    char*              name,
	size_t             minContainerSize,
	size_t             initBlockSize,
	size_t             maxBlockSize)
{
	IMemContainerManager  _    = (IMemContainerManager)self;
	IErrorLogger          elog = _->errorLogger;

	size_t         blockMaxChunkSize;
    size_t         blockSize;
	MemoryBlock    block;

	/* MemorySet is derived from MemoryContainer.
	 * First we create a base object.
	 */
	MemorySet      set = (MemorySet)memContCreate(
		                          self,
                                  container,
								  parent,
                                  MCT_MemorySet, 
	                              sizeof(SMemorySet),
	                              name);

	ASSERT(elog, set != NULL, NULL);

	initBlockSize = AlignDefault(initBlockSize);

	/* Check if initBlockSize is less than 
	 * the minimum allowed value. 
	 */
	if (initBlockSize < MEM_BLOCK_INIT_MIN_SIZE)
		initBlockSize = MEM_BLOCK_INIT_MIN_SIZE;

	maxBlockSize = AlignDefault(maxBlockSize);

	/* maxBlock should be bigger than initBlockSize. */
	if (maxBlockSize < initBlockSize)
		maxBlockSize = initBlockSize;

	set->initBlockSize = initBlockSize;
	set->maxBlockSize  = maxBlockSize;
	set->nextBlockSize = initBlockSize;

	/* chunkMaxSize can't be more than chunk_max_size 
	 * because the number of free lists is restricted.
	 */
	set->chunkMaxSize  = MEMORY_CHUNK_MAX_SIZE;

	/* Calculate the max chunk size in comparison 
	 * to the max block size. 
	 * The chunk size limit is at most 1/8 of the max block size
	 * In the case when all chunks have the maximum size 
	 * only 1/8 of the block space will be wasted.
	 */
	blockMaxChunkSize = (maxBlockSize - MEM_BLOCK_SIZE) / MAX_BLOCK_CHUNKS_NUM;
    
	/* There can be a situation when memory chunk max size is more than 
	 * the max chunk size to block. So we should syncronize this and
	 * we divide it on 2 until chunk max size becomes less than maxChunkSizeToBlock.
	 */
	while (set->chunkMaxSize + MEM_CHUNK_SIZE > blockMaxChunkSize)
		set->chunkMaxSize >>= 1;

    if (minContainerSize <= MEM_BLOCK_SIZE + MEM_CHUNK_SIZE)    
		return (MemoryContainer)set;

	/* Here minContextSize is more than the block size.
	 * In this case we allocate the first block.
	 */
	blockSize = AlignDefault(minContainerSize);

	ASSERT(elog, funcMalloc != NULL, NULL); 
    block     = (MemoryBlock)funcMalloc(blockSize);

	/* An error has happened. We should report it. */
	if (block == NULL)
	{
        showMemStat(_, topMemCont, 0);

	    elog->log(LOG_ERROR, 
		          ERROR_CODE_OUT_OF_MEMORY, 
				  "Out of memory. Failed request size: %lu", 
				  blockSize);

		return NULL;
	}

	block->memset    = set;
	block->freeStart = ((char*)block) + MEM_BLOCK_SIZE;
	block->freeEnd   = ((char*)block) + blockSize;

	/* Insert this block into the head of the blocks list. */
	block->next      = set->blockList;
	set->blockList   = block;
	//set->keeperBlock = block;

	return (MemoryContainer)set;
}