예제 #1
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/*
 * Any change of global outstanding allocation balance should come
 * from the combination of active memory account balance increase
 * and any shared header allocation (SharedChunkHeadersMemoryAccount
 * balance increase)
 */
void
test__MemoryAccounting_Allocate__ChargesOnlyActiveAccount(void **state)
{
	MemoryAccount *newActiveAccount = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);

	/* Make sure we have a new active account other than Rollover */
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount);

	assert_true(ActiveMemoryAccount == newActiveAccount);

	uint64 prevOutstanding = MemoryAccountingOutstandingBalance;

	uint64 prevSharedHeaderAlloc = SharedChunkHeadersMemoryAccount->allocated;

	void *testAlloc = palloc(NEW_ALLOC_SIZE);

	/*
	 * Any change of outstanding balance is coming from new allocation
	 * and the associated shared header allocation
	 */
	assert_true((newActiveAccount->allocated - newActiveAccount->freed) +
			(SharedChunkHeadersMemoryAccount->allocated - prevSharedHeaderAlloc) ==
					(MemoryAccountingOutstandingBalance - prevOutstanding));

	/*
	 * We need to pfree as we have allocated this memory
	 * in the TopMemoryContext with a short-living memory account
	 */
	pfree(testAlloc);
}
예제 #2
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/* Tests whether a large allocation updates balance of the active memory account */
void
test__AllocSetAllocImpl__LargeAllocInActiveMemoryAccount(void **state)
{
	MemoryAccount *newActiveAccount = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);

	/* Make sure we have a new active account other than Rollover */
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount);

	uint64 prevOutstanding = MemoryAccountingOutstandingBalance;

	uint64 prevSharedHeaderAlloc = SharedChunkHeadersMemoryAccount->allocated;

	uint64 prevActiveAlloc = ActiveMemoryAccount->allocated;

	int chunkSize = ALLOC_CHUNK_LIMIT + 1;
	/* This chunk should record newAccount as the owner */
	void *testAlloc = palloc(chunkSize);

	/*
	 * All the new allocation should go to ActiveMemoryAccount, and the
	 * SharedChunkHeadersMemoryAccount should contribute to add up to
	 * the outstanding balance change
	 */
	assert_true((newActiveAccount->allocated >= prevActiveAlloc + chunkSize) &&
			(SharedChunkHeadersMemoryAccount->allocated > prevSharedHeaderAlloc) &&
			(newActiveAccount->allocated - newActiveAccount->freed) +
			(SharedChunkHeadersMemoryAccount->allocated - prevSharedHeaderAlloc) ==
					(MemoryAccountingOutstandingBalance - prevOutstanding));

	/*
	 * We need to pfree as we have allocated this memory
	 * in the TopMemoryContext with a short-living memory account
	 */
	pfree(testAlloc);
}
예제 #3
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/* Tests whether a free operation decreases balance of only the owning account */
void
test__AllocFreeInfo__FreesOnlyOwnerAccount(void **state)
{
	MemoryAccount *newAccount = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newAccount);

	/* This chunk should record newAccount as the owner */
	void *testAlloc = palloc(NEW_ALLOC_SIZE);

	MemoryAccounting_SwitchAccount(oldActiveAccount);

	assert_true(ActiveMemoryAccount != newAccount);

	uint64 originalActiveBalance = ActiveMemoryAccount->allocated - ActiveMemoryAccount->freed;
	uint64 newAccountBalance = newAccount->allocated - newAccount->freed;
	uint64 newAccountFreed = newAccount->freed;
	uint64 sharedFreed = SharedChunkHeadersMemoryAccount->freed;
	uint64 prevOutstanding = MemoryAccountingOutstandingBalance;

	pfree(testAlloc);

	/*
	 * Make sure that the active account is unchanged while the owner account
	 * balance was reduced
	 */
	assert_true(ActiveMemoryAccount->allocated - ActiveMemoryAccount->freed == originalActiveBalance);
	/* Balance was released from newAccount */
	assert_true(newAccount->allocated - newAccount->freed <= newAccountBalance - NEW_ALLOC_SIZE);

	/* The shared header should be released */
	assert_true(SharedChunkHeadersMemoryAccount->freed - sharedFreed > 0);

	/* All the difference in outstanding balance should come from newAccount
	 * (which was the owner of the chunk) balance change and the resulting
	 * shared header release
	 */
	assert_true(prevOutstanding - MemoryAccountingOutstandingBalance ==
			newAccount->freed - newAccountFreed + SharedChunkHeadersMemoryAccount->freed - sharedFreed);
}
예제 #4
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/*
 * Tests whether we charge shared chunk header account during an allocation
 * when header sharing is not possible
 */
void
test__AllocAllocInfo__ChargesSharedChunkHeadersMemoryAccount(void **state)
{
	MemoryAccount *newActiveAccount = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);

	/* Make sure we have a new active account to force a new shared header allocation */
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount);

	uint64 prevSharedBalance = SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed;

	void *testAlloc = palloc(NEW_ALLOC_SIZE);

	uint64 newSharedBalance = SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed;

	/*
	 * A new sharedHeader should record the associated memory overhead
	 * in the SharedChunkHeadersMemoryAccount
	 */
	assert_true(prevSharedBalance < newSharedBalance);

	pfree(testAlloc);
}
예제 #5
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/* Tests whether we are promptly freeing shared header that is no longer shared */
void
test__AllocFreeInfo__FreesObsoleteHeader(void **state)
{
	MemoryAccount *newActiveAccount = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);

	/* Make sure we have a new active account to force a new shared header allocation */
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount);

	uint64 prevSharedBalance = SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed;

	void *testAlloc = palloc(NEW_ALLOC_SIZE);

	uint64 newSharedBalance = SharedChunkHeadersMemoryAccount->allocated - SharedChunkHeadersMemoryAccount->freed;

	assert_true(prevSharedBalance < newSharedBalance);

	StandardChunkHeader *header = (StandardChunkHeader *)
		((char *) testAlloc - STANDARDCHUNKHEADERSIZE);

	AllocSet set = (AllocSet)CurrentMemoryContext;

	SharedChunkHeader *headerPointer = header->sharedHeader;
	assert_true(set->sharedHeaderList == headerPointer);

	/*
	 * As no one else is using the sharedHeader of testAlloc,
	 * we should release upon pfree of testAlloc
	 */
	pfree(testAlloc);

	/*
	 * The sharedHeaderList should no longer store the sharedHeader
	 * that we have just released. Note: the headerPointer is now
	 * and invalid pointer as we have already freed the shared header
	 * memory
	 */
	assert_true(set->sharedHeaderList != headerPointer);
}
예제 #6
0
/*
 * CreateMemoryAccountImpl
 *		Allocates and initializes a memory account.
 *
 * maxLimit: The quota information of this account
 * ownerType: Gross owner type (e.g., different executor nodes). The memory
 * 		accounts are hierarchical, so using the tree location we will differentiate
 * 		between owners of same gross type (e.g., two sequential scan owners).
 * parent: The parent account of this account.
 */
static MemoryAccount*
CreateMemoryAccountImpl(long maxLimit, MemoryOwnerType ownerType, MemoryAccount* parent)
{
	/* We don't touch the oldContext. We create all MemoryAccount in MemoryAccountMemoryContext */
    MemoryContext oldContext = NULL;
	MemoryAccount* newAccount = NULL; /* Return value */
	/* Used for switching temporarily to MemoryAccountMemoryAccount ownership to account for the instrumentation overhead */
	MemoryAccount *oldAccount = NULL;

	/*
	 * Rollover is a special MemoryAccount that resides at the
	 * TopMemoryContext, and not under MemoryAccountMemoryContext
	 */
    Assert(ownerType == MEMORY_OWNER_TYPE_LogicalRoot || ownerType == MEMORY_OWNER_TYPE_SharedChunkHeader ||
    		ownerType == MEMORY_OWNER_TYPE_Rollover || ownerType == MEMORY_OWNER_TYPE_MemAccount ||
    		(MemoryAccountMemoryContext != NULL && MemoryAccountMemoryAccount != NULL));

    if (ownerType == MEMORY_OWNER_TYPE_SharedChunkHeader || ownerType == MEMORY_OWNER_TYPE_Rollover || ownerType == MEMORY_OWNER_TYPE_MemAccount || ownerType == MEMORY_OWNER_TYPE_Top)
    {
    	/* Set the "logical root" as the parent of two top account */
    	parent = MemoryAccountTreeLogicalRoot;
    }

    /*
     * Other than logical root, no long-living account should have children
     * and only logical root is allowed to have no parent
     */
    Assert((parent == NULL && ownerType == MEMORY_OWNER_TYPE_LogicalRoot) ||
    		(parent != RolloverMemoryAccount && parent != SharedChunkHeadersMemoryAccount &&
    		parent != MemoryAccountMemoryAccount));

    /*
     * Only SharedChunkHeadersMemoryAccount, Rollover, MemoryAccountMemoryAccount
     * and Top can be under "logical root"
     */
    Assert(parent != MemoryAccountTreeLogicalRoot ||
    		ownerType == MEMORY_OWNER_TYPE_LogicalRoot ||
    		ownerType == MEMORY_OWNER_TYPE_SharedChunkHeader ||
    		ownerType == MEMORY_OWNER_TYPE_Rollover ||
    		ownerType == MEMORY_OWNER_TYPE_MemAccount ||
    		ownerType == MEMORY_OWNER_TYPE_Top);

    /* Long-living accounts need TopMemoryContext */
    if (ownerType == MEMORY_OWNER_TYPE_LogicalRoot ||
    		ownerType == MEMORY_OWNER_TYPE_SharedChunkHeader ||
    		ownerType == MEMORY_OWNER_TYPE_Rollover ||
    		ownerType == MEMORY_OWNER_TYPE_MemAccount)
    {
    	oldContext = MemoryContextSwitchTo(TopMemoryContext);
    }
    else
    {
    	oldContext = MemoryContextSwitchTo(MemoryAccountMemoryContext);
        oldAccount = MemoryAccounting_SwitchAccount(MemoryAccountMemoryAccount);
    }

	newAccount = makeNode(MemoryAccount);
	InitializeMemoryAccount(newAccount, maxLimit, ownerType, parent);

	if (oldAccount != NULL)
	{
		MemoryAccounting_SwitchAccount(oldAccount);
	}

    MemoryContextSwitchTo(oldContext);

    return newAccount;
}
예제 #7
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/*
 * Tests whether we correctly allocate a new shared header and insert it
 * into the sharedHeaderList
 */
void
test__AllocAllocInfo__InsertsIntoSharedHeaderList(void **state)
{
	AllocSet set = (AllocSet)CurrentMemoryContext;

	/*
	 * This should create or reuse one of the sharedHeader
	 * in the current context's sharedHeaderList
	 */
	void *testAlloc1 = palloc(NEW_ALLOC_SIZE);

	MemoryAccount *newActiveAccount1 = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	/* Make sure we have a new active account to force a new shared header allocation */
	MemoryAccounting_SwitchAccount(newActiveAccount1);

	/* This will trigger a new sharedHeader creation because of the new ActiveMemoryAccount */
	void *testAlloc2 = palloc(NEW_ALLOC_SIZE);

	StandardChunkHeader *header1 = (StandardChunkHeader *)
		((char *) testAlloc1 - STANDARDCHUNKHEADERSIZE);

	StandardChunkHeader *header2 = (StandardChunkHeader *)
		((char *) testAlloc2 - STANDARDCHUNKHEADERSIZE);

	/* Now we are triggering a third sharedHeader creation */
	MemoryAccount *newActiveAccount2 = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	/* Make sure we have a new active account to force a new shared header allocation */
	MemoryAccounting_SwitchAccount(newActiveAccount2);

	void *testAlloc3 = palloc(NEW_ALLOC_SIZE);
	StandardChunkHeader *header3 = (StandardChunkHeader *)
		((char *) testAlloc3 - STANDARDCHUNKHEADERSIZE);

	/* Verify that the sharedHeaderList linked list looks good */
	assert_true(set->sharedHeaderList == header3->sharedHeader &&
			set->sharedHeaderList->next == header2->sharedHeader &&
			set->sharedHeaderList->next->next == header1->sharedHeader &&
			set->sharedHeaderList->next->next->next == NULL);

	/*
	 * Create one more account to force creation of another sharedHeader, which
	 * should replace the earliest sharedHeader in the sharedHeaderList. We only
	 * look ahead up to depth 3, but we maintain all the sharedHeaders in the
	 * sharedHeaderList
	 */
	MemoryAccount *newActiveAccount3 = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	MemoryAccounting_SwitchAccount(newActiveAccount3);

	void *testAlloc4 = palloc(NEW_ALLOC_SIZE);
	StandardChunkHeader *header4 = (StandardChunkHeader *)
		((char *) testAlloc4 - STANDARDCHUNKHEADERSIZE);

	/*
	 * Verify that the sharedHeaderList linked list can go beyond
	 * 3 levels of lookahead by testing linked list up to depth 4
	 */
	assert_true(set->sharedHeaderList == header4->sharedHeader &&
			set->sharedHeaderList->next == header3->sharedHeader &&
			set->sharedHeaderList->next->next == header2->sharedHeader &&
			set->sharedHeaderList->next->next->next == header1->sharedHeader &&
			set->sharedHeaderList->next->next->next->next == NULL);

	pfree(testAlloc1);
	pfree(testAlloc2);
	pfree(testAlloc3);
	pfree(testAlloc4);
}
예제 #8
0
파일: aset_test.c 프로젝트: ricky-wu/gpdb
/*
 * Tests whether header sharing works even if the desired header
 * is not at the head of sharedHeaderList
 */
void
test__AllocAllocInfo__LooksAheadInSharedHeaderList(void **state)
{
	AllocSet set = (AllocSet)CurrentMemoryContext;

	/*
	 * This should create or reuse one of the sharedHeader
	 * in the current context's sharedHeaderList
	 */
	void *testAlloc1 = palloc(NEW_ALLOC_SIZE);

	MemoryAccount *newActiveAccount1 = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	/* Make sure we have a new active account to force a new shared header allocation */
	MemoryAccount *oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount1);

	/* This will trigger a new sharedHeader creation because of the new ActiveMemoryAccount */
	void *testAlloc2 = palloc(NEW_ALLOC_SIZE);

	StandardChunkHeader *header1 = (StandardChunkHeader *)
		((char *) testAlloc1 - STANDARDCHUNKHEADERSIZE);

	StandardChunkHeader *header2 = (StandardChunkHeader *)
		((char *) testAlloc2 - STANDARDCHUNKHEADERSIZE);

	/* The old shared header should not be at the head of sharedHeaderList */
	assert_true(set->sharedHeaderList != header1->sharedHeader);
	assert_true(header1->sharedHeader != header2->sharedHeader);

	/*
	 * This should restore old active account, so any further allocation
	 * should reuse header1, which is now *not* at the head of sharedHeaderList
	 */
	MemoryAccounting_SwitchAccount(oldActiveAccount);

	void *testAlloc3 = palloc(NEW_ALLOC_SIZE);
	StandardChunkHeader *header3 = (StandardChunkHeader *)
		((char *) testAlloc3 - STANDARDCHUNKHEADERSIZE);

	/* As we switched to previous account, we should be able to share the header */
	assert_true(header3->sharedHeader == header1->sharedHeader);

	/* Now we are triggering a third sharedHeader creation */
	MemoryAccount *newActiveAccount2 = MemoryAccounting_CreateAccount(0, MEMORY_OWNER_TYPE_Exec_Hash);
	/* Make sure we have a new active account to force a new shared header allocation */
	oldActiveAccount = MemoryAccounting_SwitchAccount(newActiveAccount2);

	void *testAlloc4 = palloc(NEW_ALLOC_SIZE);
	StandardChunkHeader *header4 = (StandardChunkHeader *)
		((char *) testAlloc4 - STANDARDCHUNKHEADERSIZE);

	/* Make sure header4 got a new sharedHeader as we switched to a *new* memory account */
	assert_true(header4->sharedHeader != header1->sharedHeader &&
			header4->sharedHeader != header2->sharedHeader && header4->sharedHeader != header1->sharedHeader);

	/* And the latest sharedHeader should be at the head of sharedHeaderList */
	assert_true(header4->sharedHeader == set->sharedHeaderList);

	/*
	 * Now restore the original account, making the very original
	 * sharedHeader eligible to be reused (a 3 level reuse lookahead)
	 */
	MemoryAccounting_SwitchAccount(oldActiveAccount);

	void *testAlloc5 = palloc(NEW_ALLOC_SIZE);
	StandardChunkHeader *header5 = (StandardChunkHeader *)
		((char *) testAlloc5 - STANDARDCHUNKHEADERSIZE);

	/*
	 * Make sure we were able to dig up the original sharedHeader
	 * by digging through the sharedHeaderList
	 */
	assert_true(header5->sharedHeader == header1->sharedHeader);

	pfree(testAlloc1);
	pfree(testAlloc2);
	pfree(testAlloc3);
	pfree(testAlloc4);
	pfree(testAlloc5);
}