/* * Checks if RedZoneHandler_FlagTopConsumer() updates the CurrentVersion and * latestRunawayVersion */ void test__RedZoneHandler_FlagTopConsumer__UpdatesEventVersions(void **state) { /* Make sure the RedZoneHandler_FlagTopConsumer code is exercised */ vmemTrackerInited = true; CreateSessionStateArray(1); /* Make sure MySessionState is valid */ SessionState *one = AcquireSessionState(1 /* sessionId */, 100 /* vmem */, 1 /* activeProcessCount */); /* Ensure we can detect runaway sessions */ *isRunawayDetector = 0; will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, l, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, l, 1); static EventVersion fakeLatestRunawayVersion = 0; static EventVersion fakeCurrentVersion = 1; latestRunawayVersion = &fakeLatestRunawayVersion; CurrentVersion = &fakeCurrentVersion; RedZoneHandler_FlagTopConsumer(); assert_true(one->runawayStatus == RunawayStatus_PrimaryRunawaySession); /* Verify that the event versions were properly updated */ assert_true(*CurrentVersion == 3 && *latestRunawayVersion == 2); DestroySessionStateArray(); }
/* * Checks if SessionState_Init fails when no more SessionState entry * is available to satisfy a new request */ void test__SessionState_Init__FailsIfNoFreeSessionStateEntry(void **state) { /* Only 3 entries to exhaust the entries */ CreateSessionStateArray(3); /* These should be new */ SessionState *first = AcquireSessionState(1, gp_sessionstate_loglevel); SessionState *second = AcquireSessionState(2, gp_sessionstate_loglevel); SessionState *third = AcquireSessionState(3, gp_sessionstate_loglevel); PG_TRY(); { /* No more SessionState entry to satisfy this request */ SessionState *fourth = AcquireSessionState(4, FATAL); assert_false("No ereport(FATAL, ...) was called"); } PG_CATCH(); { } PG_END_TRY(); DestroySessionStateArray(); }
/* * Checks if SessionState_Shutdown decrements pinCount and releases * SessionState entry as appropriate. The usedList, freeList and * sessions array are also checked for sanity */ void test__SessionState_Shutdown__ReleaseSessionEntry(void **state) { /* Only 3 entries to test the reuse */ CreateSessionStateArray(3); /* These should be new */ SessionState *first = AcquireSessionState(1, gp_sessionstate_loglevel); SessionState *second = AcquireSessionState(2, gp_sessionstate_loglevel); SessionState *third = AcquireSessionState(3, gp_sessionstate_loglevel); assert_true(first != second); assert_true(second != third); SessionState *reuseFirst = AcquireSessionState(1, gp_sessionstate_loglevel); assert_true(reuseFirst == first); assert_true(reuseFirst->pinCount == 2); assert_true(AllSessionStateEntries->usedList == third && third->next == second && second->next == first); /* The entire linked list has been reversed as we shift from freeList to usedList*/ assert_true(AllSessionStateEntries->sessions[0].next == NULL && AllSessionStateEntries->sessions[1].next == &AllSessionStateEntries->sessions[0] && AllSessionStateEntries->sessions[2].next == &AllSessionStateEntries->sessions[1]); /* The last entry is at the head of the usedList */ assert_true(AllSessionStateEntries->usedList == &AllSessionStateEntries->sessions[2] && third == &AllSessionStateEntries->sessions[2]); /* All 3 entries are consumed */ assert_true(AllSessionStateEntries->freeList == NULL); /* Release 1 entry */ ReleaseSessionState(2); assert_true(AllSessionStateEntries->freeList == second); assert_true(AllSessionStateEntries->numSession == 2); /* Entry 1 had 2 pinCount. So, we need 2 release call. */ ReleaseSessionState(1); assert_true(AllSessionStateEntries->numSession == 2); /* Only 1 free entry */ assert_true(AllSessionStateEntries->freeList->next == NULL); ReleaseSessionState(1); assert_true(AllSessionStateEntries->numSession == 1); /* Only 1 used entry */ assert_true(AllSessionStateEntries->usedList->next == NULL); /* Release entry for session 3 */ ReleaseSessionState(3); assert_true(AllSessionStateEntries->numSession == 0); /* * Based on free ordering, now we have session 2 at the tail of freeList, preceeded by * session 1 and preceded by session 3. Note, the indexing starts at 0, while session * id starts at 1 */ assert_true(AllSessionStateEntries->sessions[1].next == NULL && AllSessionStateEntries->sessions[0].next == &AllSessionStateEntries->sessions[1] && AllSessionStateEntries->sessions[2].next == &AllSessionStateEntries->sessions[0]); assert_true(AllSessionStateEntries->freeList == &AllSessionStateEntries->sessions[2]); assert_true(AllSessionStateEntries->usedList == NULL); DestroySessionStateArray(); }
/* * Checks if SessionState_Init initializes a SessionState entry after acquiring */ void test__SessionState_Init__AcquiresAndInitializes(void **state) { /* Only 2 entry to test initialization */ CreateSessionStateArray(1); SessionState *theEntry = AllSessionStateEntries->freeList; theEntry->activeProcessCount = 1234; theEntry->idle_start = 1234; theEntry->cleanupCountdown = 1234; theEntry->runawayStatus = RunawayStatus_PrimaryRunawaySession; theEntry->pinCount = 1234; theEntry->sessionId = 1234; theEntry->sessionVmem = 1234; /* Mark it as acquired and see if it is released */ SpinLockAcquire(&theEntry->spinLock); assert_true(theEntry->spinLock == 1); /* These should be new */ SessionState *first = AcquireSessionState(1, gp_sessionstate_loglevel); assert_true(first == theEntry); assert_true(theEntry->activeProcessCount == 0); assert_true(theEntry->idle_start == 0); assert_true(theEntry->cleanupCountdown == CLEANUP_COUNTDOWN_BEFORE_RUNAWAY); assert_true(theEntry->runawayStatus == RunawayStatus_NotRunaway); assert_true(theEntry->pinCount == 1); assert_true(theEntry->sessionId == 1); assert_true(theEntry->sessionVmem == 0); assert_true(theEntry->spinLock == 0); DestroySessionStateArray(); }
/* * Checks if SessionState_ShmemInit initializes the usedList and freeList * properly */ void test__SessionState_ShmemInit__LinkedListSanity(void **state) { /* Only 3 entries to test the linked list sanity */ CreateSessionStateArray(3); assert_true(AllSessionStateEntries->usedList == NULL && AllSessionStateEntries->freeList == &AllSessionStateEntries->sessions[0] && AllSessionStateEntries->sessions[0].next == &AllSessionStateEntries->sessions[1] && AllSessionStateEntries->sessions[1].next == &AllSessionStateEntries->sessions[2] && AllSessionStateEntries->sessions[2].next == NULL); DestroySessionStateArray(); }
/* * Checks if SessionState_ShmemInit initializes the SessionState entries * when postmaster */ void test__SessionState_ShmemInit__InitializesWhenPostmaster(void **state) { IsUnderPostmaster = false; /* The intention is that MAX_BACKENDS here would match the value in guc.c */ #define MAX_BACKENDS 0x7fffff int allMaxBackends[] = {1, 100, MAX_BACKENDS}; for (int i = 0; i < sizeof(allMaxBackends) / sizeof(int); i++) { CreateSessionStateArray(allMaxBackends[i]); /* All the struct properties should be unchanged */ assert_true(AllSessionStateEntries->maxSession == MaxBackends); assert_true(AllSessionStateEntries->numSession == 0); assert_true(AllSessionStateEntries->freeList == AllSessionStateEntries->sessions && AllSessionStateEntries->usedList == NULL); SessionState *prev = NULL; for (int j = 0; j < MaxBackends; j++) { SessionState *cur = &AllSessionStateEntries->sessions[j]; assert_true(cur->sessionId == INVALID_SESSION_ID); assert_true(cur->cleanupCountdown == CLEANUP_COUNTDOWN_BEFORE_RUNAWAY); assert_true(cur->runawayStatus == RunawayStatus_NotRunaway); assert_true(cur->pinCount == 0); assert_true(cur->activeProcessCount == 0); assert_true(cur->idle_start == 0); assert_true(cur->sessionVmem == 0); assert_true(cur->spinLock == 0); if (prev != NULL) { assert_true(prev->next == cur); } prev = cur; } assert_true(prev->next == NULL); DestroySessionStateArray(); } }
/* * Checks if RedZoneHandler_FlagTopConsumer() reactivates the runaway detector * if there is no active session */ void test__RedZoneHandler_FlagTopConsumer__ReactivatesDetectorIfNoActiveSession(void **state) { /* Make sure the RedZoneHandler_FlagTopConsumer code is exercised */ vmemTrackerInited = true; CreateSessionStateArray(4); /* Make sure MySessionState is valid */ SessionState *one = AcquireSessionState(1 /* sessionId */, 100 /* vmem */, 0 /* activeProcessCount */); SessionState *two = AcquireSessionState(2, 101, 0); SessionState *three = AcquireSessionState(3, 100, 0); SessionState *four = AcquireSessionState(4, 99, 0); /* Ensure we can detect runaway sessions */ *isRunawayDetector = 0; will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, l, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, l, 1); static EventVersion fakeLatestRunawayVersion = 0; static EventVersion fakeCurrentVersion = 1; latestRunawayVersion = &fakeLatestRunawayVersion; CurrentVersion = &fakeCurrentVersion; RedZoneHandler_FlagTopConsumer(); /* None of them could be detected as runaway as all of them are inactive sessions */ assert_true(one->runawayStatus == RunawayStatus_NotRunaway && two->runawayStatus == RunawayStatus_NotRunaway && three->runawayStatus == RunawayStatus_NotRunaway && four->runawayStatus == RunawayStatus_NotRunaway); assert_true(*isRunawayDetector == 0); DestroySessionStateArray(); }
/* * Checks if RedZoneHandler_FlagTopConsumer() ignores the idle sessions * even if they are the top consumer */ void test__RedZoneHandler_FlagTopConsumer__IgnoresIdleSession(void **state) { /* Make sure the RedZoneHandler_FlagTopConsumer code is exercised */ vmemTrackerInited = true; CreateSessionStateArray(4); /* Make sure MySessionState is valid */ SessionState *one = AcquireSessionState(1 /* sessionId */, 100 /* vmem */, 1 /* activeProcessCount */); SessionState *two = AcquireSessionState(2, 101, 0); SessionState *three = AcquireSessionState(3, 100, 0); SessionState *four = AcquireSessionState(4, 99, 1); /* Ensure we can detect runaway sessions */ *isRunawayDetector = 0; will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, l, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, l, 1); static EventVersion fakeLatestRunawayVersion = 0; static EventVersion fakeCurrentVersion = 1; latestRunawayVersion = &fakeLatestRunawayVersion; CurrentVersion = &fakeCurrentVersion; RedZoneHandler_FlagTopConsumer(); assert_true(one->runawayStatus == RunawayStatus_SecondaryRunawaySession && two->runawayStatus == RunawayStatus_NotRunaway && three->runawayStatus == RunawayStatus_NotRunaway /* We will encounter three first, but it doesn't have active process. So, RDT will ignore it. */ && four->runawayStatus == RunawayStatus_NotRunaway); DestroySessionStateArray(); }
/* * Checks if RedZoneHandler_FlagTopConsumer() finds the top consumer */ void test__RedZoneHandler_FlagTopConsumer__FindsTopConsumer(void **state) { /* Make sure the RedZoneHandler_FlagTopConsumer code is exercised */ vmemTrackerInited = true; CreateSessionStateArray(4); /* Make sure MySessionState is valid */ SessionState *one = AcquireSessionState(1 /* sessionId */, 100 /* vmem */, 1 /* activeProcessCount */); SessionState *two = AcquireSessionState(2, 101, 1); SessionState *three = AcquireSessionState(3, 101, 1); SessionState *four = AcquireSessionState(4, 99, 1); /* Ensure we can detect runaway sessions */ *isRunawayDetector = 0; will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, l, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, l, 1); static EventVersion fakeLatestRunawayVersion = 0; static EventVersion fakeCurrentVersion = 1; latestRunawayVersion = &fakeLatestRunawayVersion; CurrentVersion = &fakeCurrentVersion; RedZoneHandler_FlagTopConsumer(); assert_true(one->runawayStatus == RunawayStatus_NotRunaway && two->runawayStatus == RunawayStatus_NotRunaway /* three is tied with two. So, won't be flagged */ && three->runawayStatus == RunawayStatus_PrimaryRunawaySession /* First detected max consumer is flagged (note the usedList is reversed, so "three" will be ahead of "two") */ && four->runawayStatus == RunawayStatus_NotRunaway); DestroySessionStateArray(); }
/* * Checks if SessionState_Shutdown marks the session clean when the pinCount * drops to 0 (i.e., releasing the entry back to the freeList) */ void test__SessionState_Shutdown__MarksSessionCleanUponRelease(void **state) { /* Only 3 entries to test the reuse */ CreateSessionStateArray(1); /* These should be new */ SessionState *first = AcquireSessionState(1, gp_sessionstate_loglevel); SessionState *reuseFirst = AcquireSessionState(1, gp_sessionstate_loglevel); SessionState *reuseAgain = AcquireSessionState(1, gp_sessionstate_loglevel); assert_true(reuseFirst == first && reuseAgain == first); assert_true(reuseFirst->pinCount == 3); /* Entry 1 had 2 pinCount. So, we need 3 release call. */ ReleaseSessionState(1); assert_true(reuseFirst->pinCount == 2 && AllSessionStateEntries->numSession == 1); ReleaseSessionState(1); assert_true(reuseFirst->pinCount == 1 && AllSessionStateEntries->numSession == 1); will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, lockid, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, lockid, 1); /* Bypass assertion */ MySessionState = first; sessionStateInited = true; will_be_called(RunawayCleaner_RunawayCleanupDoneForSession); EXPECT_EREPORT(gp_sessionstate_loglevel); /* This will finally release the entry */ SessionState_Shutdown(); assert_true(AllSessionStateEntries->numSession == 0); DestroySessionStateArray(); }
/* * Checks if SessionState_Init acquires a new entry as well as * reuse an existing entry whenever possible */ void test__SessionState_Init__AcquiresWithReuse(void **state) { /* Only 3 entries to test the reuse */ CreateSessionStateArray(3); /* These should be new */ SessionState *first = AcquireSessionState(1, gp_sessionstate_loglevel); SessionState *second = AcquireSessionState(2, gp_sessionstate_loglevel); SessionState *third = AcquireSessionState(3, gp_sessionstate_loglevel); assert_true(first != second); assert_true(first != third); assert_true(second != third); SessionState *reuseFirst = AcquireSessionState(1, gp_sessionstate_loglevel); assert_true(reuseFirst == first); assert_true(reuseFirst->pinCount == 2); assert_true(AllSessionStateEntries->usedList == third && third->next == second && second->next == first); DestroySessionStateArray(); }
/* * Checks if SessionState_Init initializes the global variables * such as MySessionState and sessionStateInited properly */ void test__SessionState_Init__TestSideffects(void **state) { /* Only 2 entry to test initialization */ CreateSessionStateArray(1); will_be_called_count(LWLockAcquire, 1); will_be_called_count(LWLockRelease, 1); expect_any_count(LWLockAcquire, lockid, 1); expect_any_count(LWLockAcquire, mode, 1); expect_any_count(LWLockRelease, lockid, 1); assert_true(MySessionState == NULL); assert_true(sessionStateInited == false); EXPECT_EREPORT(gp_sessionstate_loglevel); SessionState_Init(); assert_true(NULL != MySessionState); assert_true(sessionStateInited); DestroySessionStateArray(); }