コード例 #1
0
ファイル: processhelper.c プロジェクト: riryk/RussoDB
/* Duplicate a handle for usage in a child process,
 * and write the child process instance
 * of the handle to the parameter file.
 */
Bool getDuplicatedHandle(
    void*            self,
    HANDLE*          dest,
    HANDLE           src,
    HANDLE           childProcess)
{
    IProcessManager _      = (IProcessManager)self;
    IErrorLogger    elog   = _->errorLogger;
    HANDLE		    hChild = INVALID_HANDLE_VALUE;

    if (!DuplicateHandle(GetCurrentProcess(),
                         src,
                         childProcess,
                         &hChild,
                         0,
                         TRUE,
                         DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS))
    {
        elog->log(LOG_LOG,
                  ERROR_CODE_DUPLICATE_HANDLE_FAILED,
                  "could not duplicate handle to be written to backend parameter file: error code %lu",
                  GetLastError());

        return False;
    }

    *dest = hChild;
    return True;
}
コード例 #2
0
ファイル: threadhelper.c プロジェクト: riryk/RussoDB
TThread startThread(
    void*            self,
	THREAD_FUNC      func, 
	void*            param, 
	TThreadId        threadid)
{
    IThreadHelper _    = (IThreadHelper)self;
	IErrorLogger  elog = _->errorLogger;

    TThread threadHandle = CreateThread(
            NULL, 
            0,    
            func, 
            param,
            0,
            &threadid);
     
    if (threadHandle == NULL)
        elog->log(LOG_ERROR,
			      ERROR_CODE_CREATE_THREAD_FAILED,
			      "could not create a thread: error code %lu",
                  GetLastError());

	return threadHandle;
}
コード例 #3
0
ファイル: threadhelper.c プロジェクト: riryk/RussoDB
void waitForMultipleEvents(
	void*          self,
	TEvent*        eventsToWait,
	int            eventsCount,
	Bool           waitAll)
{
    IThreadHelper  _    = (IThreadHelper)self;
	IErrorLogger   elog = _->errorLogger;

	DWORD          result;

	result = WaitForMultipleObjects(
		        eventsCount,
                eventsToWait,
                waitAll,
                INFINITE);

    switch (result)
	{
	/* In this case we have successfully waited for the event. */
	case WAIT_OBJECT_0:
        elog->log(LOG_LOG, 
		          0, 
				  "Successfully waited for the events"); 
		break;
    
	/* When we are here, probably some error has happened. */
    default:
        elog->log(LOG_ERROR, 
		          ERROR_CODE_WAIT_FOR_SINGLE_OBJECT_FAILED, 
				  "Wait for single object failed: error code %lu",
				  GetLastError()); 
		break;
	}
}
コード例 #4
0
ファイル: latchmanager.c プロジェクト: riryk/RussoDB
Latch initLatch(void* self)
{
	ILatchManager   _    = (ILatchManager)self;
	IErrorLogger    elog = _->errorLogger;
	IMemoryManager  mm   = _->memManager;

    SECURITY_ATTRIBUTES   sa;
	Latch                 latch;

	latch = (Latch)mm->alloc(sizeof(SLatch));

	ASSERT_VOID(elog, latch != NULL);

	latch->isset   = False;
	latch->ownerid = 0;
	latch->shared  = True;

    memset(&sa, 0, sizeof(sa)); 
	sa.nLength        = sizeof(sa);
	sa.bInheritHandle = True;

	latch->event = CreateEvent(&sa, TRUE, FALSE, NULL);
	if (latch->event == NULL)
		elog->log(LOG_ERROR, 
		          ERROR_CODE_GENERAL, 
				  "CreateEvent failed: error code %lu", 
				  GetLastError());

	return latch;
}
コード例 #5
0
ファイル: processhelper.c プロジェクト: riryk/RussoDB
BackendParams  restoreBackendParamsFromSharedMemory(void* self)
{
    IProcessManager  _      = (IProcessManager)self;
    IErrorLogger     elog   = _->errorLogger;
    IMemoryManager   memMan = _->memManager;

    BackendParams    paramSm;
    BackendParams    paramSmCpy = (BackendParams)memMan->alloc(sizeof(SBackendParams));

    HANDLE           hMapFile;

    IMemoryManager   memManager;

    hMapFile = OpenFileMapping(
                   FILE_MAP_ALL_ACCESS,
                   FALSE,
                   sharedMemParamsName);

    if (hMapFile == NULL)
        elog->log(LOG_ERROR,
                  ERROR_CODE_FILE_OPEN_MAPPING_FAILED,
                  "could not open file mapping object: error code %lu",
                  GetLastError());

    /* Maps a view of a file mapping into the address space of a calling process. */
    paramSm = (BackendParams)
              MapViewOfFile(
                  hMapFile,
                  FILE_MAP_ALL_ACCESS,
                  0,
                  0,
                  sizeof(SBackendParams));
    if (!paramSm)
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_MAP_MEMORY_TO_FILE,
                  "could not map backend parameter memory: error code %lu",
                  GetLastError());

        CloseHandle(paramSm);
        return -1;
    }

    memcpy(paramSmCpy, paramSm, sizeof(SBackendParams));

    if (!UnmapViewOfFile(paramSm))
        elog->log(LOG_ERROR,
                  ERROR_CODE_UNMAP_VIEW_OF_FILE,
                  "could not unmap view of backend parameter file: error code %lu",
                  GetLastError());

    if (!CloseHandle(hMapFile))
        elog->log(LOG_ERROR,
                  ERROR_CODE_CLOSE_HANDLER_FAILED,
                  "could not close handle to backend parameter file: error code %lu",
                  GetLastError());

    return paramSmCpy;
}
コード例 #6
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
/* 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;
}
コード例 #7
0
ファイル: processhelper.c プロジェクト: riryk/RussoDB
/* Set a privilege to a token. */
BOOL SetPrivilege(
    void*            self,
    HANDLE           hToken,             /* access token handle */
    LPCTSTR          lpszPrivilege,      /* name of privilege to enable/disable */
    BOOL             bEnablePrivilege)   /* to enable or disable privilege */
{
    IProcessManager  _    = (IProcessManager)self;
    IErrorLogger     elog = _->errorLogger;

    TOKEN_PRIVILEGES tp, prevstate;
    LUID             luid;
    DWORD            retlen;

    /* lookup privilege on local system */
    if (!LookupPrivilegeValue(
                NULL,
                lpszPrivilege,
                &luid))
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_LOOKUP_PRIVILEGE_FAILED,
                  "lookup privilege value error: error code %lu",
                  GetLastError());

        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;

    if (bEnablePrivilege)
        tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    else
        tp.Privileges[0].Attributes = 0;

    /* Enable or disable the privilege. */
    if (!AdjustTokenPrivileges(
                hToken,
                FALSE,
                &tp,
                sizeof(TOKEN_PRIVILEGES),
                &prevstate,
                &retlen))
    {
        int error = GetLastError();

        elog->log(LOG_ERROR,
                  ERROR_CODE_ADJUST_PRIVILEGE_FAILED,
                  "adjust privilege value error: error code %lu",
                  error);

        return FALSE;
    }

    return TRUE;
}
コード例 #8
0
ファイル: latchmanager.c プロジェクト: riryk/RussoDB
void waitLatch(
    void*          self,
	Latch          latch)
{
	ILatchManager  _    = (ILatchManager)self;
	ISignalManager sm   = _->signalManager;
    IErrorLogger   elog = _->errorLogger;

	DWORD		   wait_result;
    HANDLE		   events[2];
	HANDLE		   latchevent = latch->event;
	int			   numevents  = 2;
    int			   result     = 0;

	events[0] = signalEvent;
    events[1] = latchevent;

    sm->dispatchQueuedSignals();

    do
	{
        wait_result = WaitForMultipleObjects(numevents, events, FALSE, INFINITE);
        
        if (wait_result == WAIT_FAILED)
		{
			int lastError = GetLastError();

            elog->log(LOG_ERROR, 
		          ERROR_CODE_WAIT_FOR_MULTIPLE_OBJECTS_FAILED, 
				  "ResetEvent failed: error code %lu", 
	 			  lastError);
		}

        if (wait_result == WAIT_OBJECT_0)
			sm->dispatchQueuedSignals();

		if (wait_result == WAIT_OBJECT_0 + 1)
            break; 
	} 
	while (result == 0);

	return result;
}
コード例 #9
0
ファイル: threadhelper.c プロジェクト: riryk/RussoDB
void threadHelpCtor(
    void*            self,
    sleepFunc        slpFuncParam,
	Bool             includeStartThreadEvent)
{
    IThreadHelper    _    = (IThreadHelper)self;
	IErrorLogger     elog = _->errorLogger;

    slpFunc = slpFuncParam;
    ASSERT_VOID(elog, slpFunc != NULL);

	if (!includeStartThreadEvent)
		return;

	threadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (threadStartEvent == NULL)
        elog->log(LOG_FATAL, 
		          ERROR_CODE_CREATE_EVENT_FAILED, 
				  "Could not create signal event: error code %lu",
				  GetLastError());
}
コード例 #10
0
ファイル: processhelper.c プロジェクト: riryk/RussoDB
TProcess startSubProcess(void* self, int argc, char* argv[])
{
    IProcessManager _    = (IProcessManager)self;
    IErrorLogger    elog = _->errorLogger;

    STARTUPINFO          si;
    PROCESS_INFORMATION  pi;
    SECURITY_ATTRIBUTES  sa;
    BackendParams		 paramSm;
    char		         paramSmStr[32];
    char                 commandLine[MAX_PATH * 2];
    int                  cmdCharCount;
    HANDLE               paramMap;
    DeadChildInfo        childInfo;
    HANDLE               tokenHandle = NULL;

    int                  i, j;

    ASSERT(elog, argv != NULL, -1);
    ASSERT(elog, argv[0] != NULL, -1);
    ASSERT(elog, argv[1] != NULL, -1);
    ASSERT(elog, argv[2] == NULL, -1);

    /* Set up shared memory for parameter passing */
    ZeroMemory(&sa, sizeof(sa));
    sa.nLength        = sizeof(sa);
    sa.bInheritHandle = TRUE;

    if (!OpenProcessToken(
                GetCurrentProcess(),
                TOKEN_ALL_ACCESS,
                &tokenHandle))
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_OPEN_PROCESS_TOKEN,
                  "could not open process token: error code %lu",
                  GetLastError());

        return -1;
    }

    if (!SetPrivilege(
                _,
                tokenHandle,
                SE_CREATE_GLOBAL_NAME,
                True))
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_SET_PRIVILEDGE_FAILED,
                  "could not open process token: error code %lu",
                  GetLastError());

        return -1;
    }

    /* If the first parameter is INVALID_HANDLE_VALUE,
     * the calling process must also specify a size
     * for the file mapping object. In this scenario,
     * CreateFileMapping creates a file mapping object
     * of a specified size that is backed by the system paging file
     * instead of by a file in the file system.
     */
    paramMap = CreateFileMapping(INVALID_HANDLE_VALUE,
                                 &sa,
                                 PAGE_READWRITE,
                                 0,
                                 sizeof(SBackendParams),
                                 sharedMemParamsName);

    if (paramMap == NULL || paramMap == INVALID_HANDLE_VALUE)
    {
        int error = GetLastError();

        elog->log(LOG_ERROR,
                  ERROR_CODE_CREATE_FILE_MAP_FAILED,
                  "could not create file mapping: error code %lu",
                  error);

        return -1;
    }

    sharedMemID       = paramMap;
    sharedMemSegmSize = sizeof(SBackendParams);

    /* Maps a view of a file mapping into the address space of a calling process. */
    paramSm = MapViewOfFile(paramMap, FILE_MAP_WRITE, 0, 0, sizeof(SBackendParams));
    if (!paramSm)
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_MAP_MEMORY_TO_FILE,
                  "could not map backend parameter memory: error code %lu",
                  GetLastError());

        CloseHandle(paramSm);
        return -1;
    }

    sprintf(paramSmStr, "%lu", (DWORD)paramSm);
    argv[2] = paramSmStr;

    cmdCharCount = sizeof(commandLine);
    commandLine[cmdCharCount - 1] = '\0';
    commandLine[cmdCharCount - 2] = '\0';

    snprintf(commandLine, cmdCharCount - 1, "\"%s\"", ExecPath);

    i = 0;
    while (argv[++i] != NULL)
    {
        j = strlen(commandLine);
        snprintf(commandLine + j, sizeof(commandLine) - 1 - j, " \"%s\"", argv[i]);
    }

    if (commandLine[sizeof(commandLine) - 2] != '\0')
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_PROC_CMD_LINE_TO_LONG,
                  "subprocess command line too long");
        return -1;
    }

    memset(&pi, 0, sizeof(pi));
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);

    /* Create the subprocess in a suspended state.
     * This will be resumed later,
     * once we have written out the parameter file.
     * If this parameter TRUE, each inheritable handle
     * in the calling process is inherited by the new process.
     * If the parameter is FALSE, the handles are not inherited.
     * Note that inherited handles have the same value
     * and access rights as the original handles.
     */
    if (!CreateProcess(NULL, commandLine, NULL,
                       NULL, TRUE, CREATE_SUSPENDED,
                       NULL, NULL, &si, &pi))
    {
        elog->log(LOG_ERROR,
                  ERROR_CODE_CREATE_PROCESS_FAILED,
                  "CreateProcess call failed: (error code %lu)",
                  GetLastError());

        return -1;
    }

    if (!fillBackandParams(
                _,
                paramSm,
                pi.hProcess,
                pi.dwProcessId))
    {
        /* Delete the process */
        if (!TerminateProcess(pi.hProcess, 255))
            elog->log(LOG_ERROR,
                      ERROR_CODE_TERMINATE_PROCESS_FAILED,
                      "Terminate process failed: (error code %lu)",
                      GetLastError());

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return -1;
    }

    /* Drop the handler to the shared memory.
     * Now the shared memory has already been passed
     * along to the child process.
     */
    if (!UnmapViewOfFile(paramSm))
        elog->log(LOG_ERROR,
                  ERROR_CODE_UNMAP_VIEW_OF_FILE,
                  "could not unmap view of backend parameter file: error code %lu",
                  GetLastError());

    if (!CloseHandle(paramMap))
        elog->log(LOG_ERROR,
                  ERROR_CODE_CLOSE_HANDLER_FAILED,
                  "could not close handle to backend parameter file: error code %lu",
                  GetLastError());

    /* All variables are written out, so we can resume the thread */
    if (ResumeThread(pi.hThread) == -1)
    {
        /* Delete the process */
        if (!TerminateProcess(pi.hProcess, 255))
        {
            elog->log(LOG_ERROR,
                      ERROR_CODE_TERMINATE_PROCESS_FAILED,
                      "Terminate process failed: (error code %lu)",
                      GetLastError());

            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
            return -1;
        }

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);

        elog->log(LOG_ERROR,
                  ERROR_CODE_RESUME_THREAD_FAILED,
                  "Terminate process failed: (error code %lu)",
                  GetLastError());
        return -1;
    }

    childInfo = malloc(sizeof(SDeadChildInfo));
    if (childInfo == NULL)
        elog->log(LOG_FATAL,
                  ERROR_CODE_OUT_OF_MEMORY,
                  "out of memory");

    childInfo->procHandle = pi.hProcess;
    childInfo->procId     = pi.dwProcessId;

    /* Directs a wait thread in the thread pool to wait on the object.
     * The wait thread queues the specified callback function to the thread pool
     * when one of the following occurs:
     *  - The specified object is in the signaled state.
     *  - The time-out interval elapses.
     * When a process terminates, the state of the process object
     * becomes signaled, releasing any threads
     * that had been waiting for the process to terminate.
     */
    if (!RegisterWaitForSingleObject(
                &childInfo->waitHandle,
                pi.hProcess,
                deadChildProcCallBack,
                childInfo,
                INFINITE,
                WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD))
        elog->log(LOG_ERROR,
                  ERROR_CODE_REGISTER_WAIT_HANDLER_FAILED,
                  "Could not register process for wait: error code %lu",
                  GetLastError());

    /* Don't close pi.hProcess here -
     * the wait thread needs access to it.
     */
    CloseHandle(pi.hThread);

    return pi.hProcess;
}
コード例 #11
0
Hashtable createHashtable(
    void*              self,
	char*              name, 
	long               maxItemsNum, 
	HashtableSettings  set, 
	int                setFlags)
{
	IHashtableManager _       = (IHashtableManager)self;
	IErrorLogger      elog    = (IErrorLogger)_->errorLogger;
	ISpinLockManager  slog    = (ISpinLockManager)_->spinLockHelper; 

	Hashtable         tbl;
	int               nHashLists;
	int               nSegs;
	int               segLLSize;
	uint              elemSize;
    HashSegment*      segP; 
	ulong             tblSegSize;

	/* Initialize the hash header, plus a copy of the table name.
	 * First sizeof(Hashtable) bytes are allocated for a hash table.
	 * The next strlen(Name) are allocated for the name.
	 * In this way we unate one malloc call for struct SHashtable with another 
	 * malloc for char* name.
	 */
	tbl = (Hashtable)_->memManager->alloc(sizeof(SHashtable) + strlen(name) + 1);
	memset(tbl, 0, sizeof(SHashtable));

	/* Adding one to a pointer means "produce a pointer to the object 
	 * that comes in memory right after this one," 
	 * which means that the compiler automatically scales up 
	 * whatever you're incrementing the pointer with 
	 * by the size of the object being pointed at. */
	tbl->name = (char*)(tbl + 1);
	strcpy(tbl->name, name);

    setDefaults(tbl);

	if (setFlags & HASH_FUNC)
		tbl->hashFunc = set->hashFunc;

	if (tbl->hashFunc == hashFuncStr)
		tbl->hashCmp = hashCmpFuncStr;

	if (setFlags & HASH_CMP)
		tbl->hashCmp = set->hashCmp;

    if (tbl->hashFunc == hashFuncStr)
		tbl->hashCpy = (hashCpyFunc)strcpy;

    if (setFlags & HASH_KEYCPY)
		tbl->hashCpy = set->hashCpy;

	if (setFlags & HASH_ITEM)
	{
	    tbl->keyLen = set->keyLen;
	    tbl->valLen = set->valLen;
	}

    if (setFlags & HASH_SEG)
	{
		tbl->segmSize = set->segmSize;
		tbl->segmShift = set->segmShift;
	}

    if (setFlags & HASH_LIST_SIZE)
	{
		tbl->segmsAmount = set->segmsAmount;
		tbl->maxSegmsAmount = set->maxSegmsAmount;
		tbl->hashListSize = set->hashListSize;
	}

	if (setFlags & HASH_WITHOUT_EXTENTION)
	{
        tbl->isWithoutExtention = set->isWithoutExtention;
	}

	if (setFlags & HASH_PARTITION)
	{
		Bool  isNumPowerOf2 = tbl->partNum == _->commonHelper->nextPowerOf2(tbl->partNum);

		/* First of all we need to check if the hashtable is located
		 * in the shared memory. Applying partitions to a hashtable
		 * which is located in the local memory is pointless because 
		 * no contention is applied. 
		 */
		ASSERT(elog, setFlags & HASH_SHARED_MEMORY, NULL);
        
		/* We should check if the number of partiotions is really power of 2 */
        ASSERT(elog, isNumPowerOf2, NULL);

		tbl->partNum = set->partNum; 
	}

	if (IS_TABLE_PARTITIONED(tbl))
		slog->spinLockInit(slog, &(tbl->mutex));

	nHashLists = (maxItemsNum - 1) / tbl->hashListSize + 1;
    nHashLists = _->commonHelper->nextPowerOf2(nHashLists);

	tbl->lowMask  = _->hashtableHelper->calcLowMask(nHashLists);
	tbl->highMask = _->hashtableHelper->calcHighMask(nHashLists);

	nSegs = _->hashtableHelper->calcSegmsNum(nHashLists, tbl->segmSize);

	tbl->numHashLists = nHashLists;
	tbl->segments = (AHashSegment)_->memManager->alloc(tbl->segmsAmount * sizeof(HashSegment));
    
    tblSegSize = tbl->segmSize;
	/* Allocate initial segments */
	for (segP = tbl->segments; tbl->nSegs < nSegs; tbl->nSegs++, segP++)
	{
		segLLSize = tblSegSize * sizeof(HashList);
		*segP = (HashSegment)(AHashList)_->memManager->alloc(segLLSize);
	    memset(*segP, 0, segLLSize);
	}
    
    /* Our element consists of a header and data sp that the size 
     * is sum of the header's size and data's size. 
	 * Header also includes aligned key. 
	 */
    elemSize = HASH_ELEM_SIZE(tbl);
	tbl->numItemsToAlloc = itemsNumToAlloc(elemSize);

	if (!initHashtable(_, tbl))
	{
        elog->log(LOG_ERROR,
			      ERROR_CODE_FAILED_TO_INIT_HASHTABLE,
				  "Spinlock exceeded max allowed sleep counts: %d");        

		return NULL;
	}

	if (setFlags & HASH_SEG || maxItemsNum < tbl->numItemsToAlloc)
	{
        if (!allocNewItems(_, tbl))
		{
             elog->log(LOG_ERROR,
			      ERROR_CODE_OUT_OF_MEMORY,
				  "Out of memory");        

			 return NULL;
		}

		return NULL;
	}

	return tbl;
}
コード例 #12
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
/* 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;
}
コード例 #13
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
/* Frees a piece of memory that have been allocated
 * as a chunk. The function converts this memory address
 * to a chunk and checks how this chunks has been allocated.
 * If it was like a full block we should free this block.
 * If is was an ordinary chunk we give it back to the freelist
 * for recycling.
 */
void freeChunk(
    void*          self,
	void*          mem)
{
    IMemContainerManager  _    = (IMemContainerManager)self;
	IErrorLogger          elog = _->errorLogger;

    MemoryChunk  chunk;
	MemorySet    set;
	int          ind;

	/* Get a pointer to MemoryChunk header. */
	chunk  = (MemoryChunk)((char*)mem - MEM_CHUNK_SIZE);     
	set    = chunk->memsetorchunk;

	/* If the chunk's size is larger than chunk max size 
	 * we have allocated an entire block. So that we have 
	 * to find and free this block.
	 */
	if (chunk->size > set->chunkMaxSize)
	{
        /* Try to find the corresponding block first 
		 */
		MemoryBlock   block     = set->blockList;
        MemoryBlock   prevblock = NULL;

		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;
		}

		/* Remove the block from the block list */
		if (prevblock == NULL)
			set->blockList  = block->next;
		else
			prevblock->next = block->next;
        
		ASSERT_VOID(elog, funcFree != NULL); 
		funcFree(block);

		return;
	}

	/* Now we have a normal case and the chunk is small
	 * So we should return it to the free list.
	 */
	ind = calculateFreeListIndex(chunk->size);

	/* Insert into the head of the free list. */
	chunk->memsetorchunk = (void*)set->freelist[ind];
    set->freelist[ind]   = chunk;
}
コード例 #14
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
/* 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;
}
コード例 #15
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
void* allocateMemory(
    void*                   self,
    MemoryContainer         container, 
	size_t                  size)
{   
	IMemContainerManager  _    = (IMemContainerManager)self;
	IErrorLogger          elog = _->errorLogger;
    
	Bool                  isContValid = MemoryContainerIsValid(container);
    Bool                  isSizeValid = MemAllocSizeIsValid(size);

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

    void*                 chunkPtr;
    int			          freeListInd;

	size_t		          chunkSize;
	size_t		          blockSize;

	/* Assert if the container is valid. */
    ASSERT_ARG(elog, isContValid, NULL); 
	ASSERT(elog, set->chunkMaxSize > 0, NULL);

	if (!isSizeValid)
		elog->log(LOG_ERROR, -1, "Allocate memory request size: %lu is invalid", size);

	/* In this case the requested memory size 
	 * is more than the max chunk size. So that
	 * we can't allocate a memory chunk.
	 * In this case we allocate a new whole block.
	 */
	if (size > set->chunkMaxSize)
        return allocateChunkBlock(_, size, container);

	/* The size of the chunk is too small to be an entire block.
	 * In this case we should treat it as a chunk.
	 * First of all we should look at the free list if 
	 * there is a free chunk that can come up to our 
	 * memory request.
	 */
    freeListInd = calculateFreeListIndex(size);
	chunk       = set->freelist[freeListInd];

	if (chunk != NULL)
	{
		ASSERT(elog, chunk->size > size, NULL);

		/* We remove the chunk from the head of the free list. */
		set->freelist[freeListInd] = (MemoryChunk)chunk->memsetorchunk;

		/* MemSetOrChunk now points to the parent memory set */
		chunk->memsetorchunk = set;
        chunk->sizeRequested = size;		

        chunkPtr = MemoryChunkGetPointer(chunk);
		return chunkPtr;
	}

	/* Now we should calculate the chunk size.
	 * freeListInd = log2(chunksCount)
	 * 2^(freeListInd) = 2^(log2(chunksCount))
	 * chunksCount = 2 ^ freeListInd;
	 * 1 << 10 = 2 ^ 10. So we should shift left 
	 * on freeListInd positions
	 * chunksCount = 1 << freeListInd;
	 * And then we should multiple on 2 ^ MIN_CHUNK_POWER_OF_2
	 */
	chunkSize = (1 << MIN_CHUNK_POWER_OF_2) << freeListInd;
    ASSERT(elog, chunkSize > size, NULL); 

	/* Take the first block in the blocks list */
	block = set->blockList;

	/* If the actual active block does not contain enough
	 * free space for the chunk we should create a new block.
	 */
	if (block == NULL || !checkFreeBlockSpace(_, set, block, chunkSize))
        block = allocateBlock(_, chunkSize, container);

    /* do the allocation */
	chunk = (MemoryChunk)block->freeStart;

	/* Move the block's free start pointer */
	block->freeStart += (chunkSize + MEM_CHUNK_SIZE);

	chunk->memsetorchunk = (void*)set;
	chunk->size          = chunkSize;
	chunk->sizeRequested = size;		

    chunkPtr = MemoryChunkGetPointer(chunk);
	return chunkPtr;
}
コード例 #16
0
ファイル: memcontainermanager.c プロジェクト: riryk/RussoDB
/* This is also an auxiliary function for allocateMemory method.
 * It allocates a new block and the whole memory is free.
 * The difference between allocateBlock and allocateChunkBlock
 * is that allocateChunkBlock gives the whole memory to a chunk
 * and its free list is always empty. allocateBlock creates 
 * a new block and reclaims whole memory to its free list.
 */
void* allocateBlock(
    void*             self,
	size_t            chunkSize,
	MemoryContainer   container)
{
	IMemContainerManager  _     = (IMemContainerManager)self;
	IErrorLogger          elog  = _->errorLogger;

	MemorySet	          set   = (MemorySet)container;
	MemoryBlock           block;

    size_t		  requiredSize; 
	size_t        blockSize;
    
	ASSERT(elog, set->nextBlockSize > 0, NULL);
    ASSERT(elog, set->maxBlockSize > 0, NULL);

	/* Set blockSize. We keep track of all block sizes
	 * And we allocate blocks in increase order of their size.
	 * We start from initBlockSize and always double the blockSize
	 * until we reach maxBlockSize.
	 */
	blockSize = set->nextBlockSize;
    set->nextBlockSize <<= 1;
	if (set->nextBlockSize > set->maxBlockSize)
        set->nextBlockSize = set->maxBlockSize;

    /* Block size should at least cover the chunk */
	requiredSize = chunkSize + MEM_BLOCK_SIZE + MEM_CHUNK_SIZE;
	while (blockSize < requiredSize)
		blockSize <<= 1;

	/* Allocate a new block */
	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) + MEM_BLOCK_SIZE;
	block->freeEnd   = ((char*)block) + blockSize; 

	/* If the block size is an initial block size,
	 * we adjust a keeper block.
	 */
	// if (set->keeperBlock == NULL && blockSize == set->initBlockSize)
	//	set->keeperBlock = block;

	/* Insert the new block into the head of the freelist */
	block->next    = set->blockList;
	set->blockList = block;

	return block;
}