/* * Acquires a SessionState entry for the specified sessionid. If an existing entry * is found, this method reuses that entry */ static SessionState* AcquireSessionState(int sessionId, int vmem, int activeProcessCount) { 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); /* Keep the assertions happy */ gp_session_id = sessionId; sessionStateInited = false; MySessionState = NULL; EXPECT_EREPORT(gp_sessionstate_loglevel); SessionState_Init(); if (vmem >= 0) { MySessionState->sessionVmem = vmem; } if (activeProcessCount >= 0) { MySessionState->activeProcessCount = activeProcessCount; } return MySessionState; }
/* Releases a SessionState entry for the specified sessionId */ static void ReleaseSessionState(int sessionId) { /* We call shutdown twice */ will_be_called_count(LWLockAcquire, 2); will_be_called_count(LWLockRelease, 2); expect_any_count(LWLockAcquire, lockid, 2); expect_any_count(LWLockAcquire, mode, 2); expect_any_count(LWLockRelease, lockid, 2); gp_session_id = sessionId; /* First find the previously allocated session state */ SessionState *foundSessionState = AcquireSessionState(sessionId, gp_sessionstate_loglevel); assert_true(foundSessionState->sessionId == sessionId); /* * It was pre-allocated and we incremented the pinCount * for finding it */ assert_true(foundSessionState->pinCount > 1); /* Satisfy assertion */ sessionStateInited = true; EXPECT_EREPORT(gp_sessionstate_loglevel); /* Undo for our search pinCount */ SessionState_Shutdown(); /* The pinCount should not drop to 0 as we just undid our own increment */ assert_true(foundSessionState->pinCount >= 1); MySessionState = foundSessionState; sessionStateInited = true; /* * If we are releasing this SessionState permanently, we need to ensure * that RunawayCleaner_RunawayCleanupDoneForSession() will be called */ if (foundSessionState->pinCount == 1) { will_be_called(RunawayCleaner_RunawayCleanupDoneForSession); } EXPECT_EREPORT(gp_sessionstate_loglevel); /* Undo one more to truly undo previously acquired one */ SessionState_Shutdown(); }
/* * Acquires a SessionState entry for the specified sessionid. If an existing entry * is found, this method reuses that entry */ static SessionState* AcquireSessionState(int sessionId, int loglevel) { 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); /* Keep the assertions happy */ gp_session_id = sessionId; sessionStateInited = false; MySessionState = NULL; EXPECT_EREPORT(loglevel); SessionState_Init(); return MySessionState; }
/* * A utility method that can check header version mismatch error message * for different offsets. E.g., mismatch by 1 version, or -1 version tests * the error message when module magic's header version is ahead by 1 * or trailing by 1 */ static void CheckHeaderVersionMismatch(int diffOffset) { Pg_magic_struct module_magic = PG_MODULE_MAGIC_DATA; module_magic.headerversion = magic_data.headerversion + diffOffset; SetExpectedErrorMessage(module_magic, module_magic.headerversion); EXPECT_EREPORT(ERROR); PG_TRY(); { incompatible_module_error("test", &module_magic); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); }
/* * Tests if we don't throw a version mismatch error if the header versions are identical */ static void test__incompatible_module_error__headerversion_identical(void **state) { /* Module magic is identical to ours */ Pg_magic_struct module_magic = PG_MODULE_MAGIC_DATA; /* We should expect a "default" error */ snprintf(expectedErrorMsg, 255, "Magic block has unexpected length or padding difference."); EXPECT_EREPORT(ERROR); PG_TRY(); { incompatible_module_error("test", &module_magic); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); }
/* * Tests if we error out if the loaded module's expected Pg_magic_struct * is smaller (i.e., we have newer fields) */ static void test__incompatible_module_error__struct_size_mismatch(void **state) { Pg_magic_struct module_magic = PG_MODULE_MAGIC_DATA; /* Simulate a smaller structure for the module's Pg_magic_struct */ module_magic.len = offsetof(Pg_magic_struct, headerversion); SetExpectedErrorMessage(module_magic, 0); EXPECT_EREPORT(ERROR); PG_TRY(); { incompatible_module_error("test", &module_magic); assert_true(false); } PG_CATCH(); { } PG_END_TRY(); }
/* * 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 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(); }
/* * Checks if RunawayCleaner_StartCleanup() starts the cleanup process if * all conditions are met (i.e., no commit is in progress and vmem tracker * is initialized) */ void test__RunawayCleaner_StartCleanup__StartsCleanupIfPossible(void **state) { InitFakeSessionState(2 /* activeProcessCount */, 2 /* cleanupCountdown */, RunawayStatus_PrimaryRunawaySession /* runawayStatus */, 2 /* pinCount */, 12345 /* vmem */); static fakeLatestRunawayVersion = 10; latestRunawayVersion = &fakeLatestRunawayVersion; *latestRunawayVersion = 10; /* * Set beginCleanupRunawayVersion to less than *latestRunawayVersion * to trigger a cleanup */ beginCleanupRunawayVersion = 1; endCleanupRunawayVersion = 1; isProcessActive = true; /* Make sure the cleanup goes through */ vmemTrackerInited = true; CritSectionCount = 0; InterruptHoldoffCount = 0; /* We need a valid gp_command_count to execute cleanup */ gp_command_count = 1; will_return(superuser, false); #ifdef FAULT_INJECTOR expect_value(FaultInjector_InjectFaultIfSet, identifier, RunawayCleanup); expect_value(FaultInjector_InjectFaultIfSet, ddlStatement, DDLNotSpecified); expect_value(FaultInjector_InjectFaultIfSet, databaseName, ""); expect_value(FaultInjector_InjectFaultIfSet, tableName, ""); will_be_called(FaultInjector_InjectFaultIfSet); #endif EXPECT_EREPORT(ERROR); PG_TRY(); { RunawayCleaner_StartCleanup(); assert_false("Cleanup didn't throw error"); } PG_CATCH(); { } PG_END_TRY(); assert_true(beginCleanupRunawayVersion == *latestRunawayVersion); /* We should not finish the cleanup as we errored out */ assert_true(endCleanupRunawayVersion == 1); /* cleanupCountdown shouldn't change as we haven't finished cleanup */ assert_true(MySessionState->cleanupCountdown == 2); /* * If we call RunawayCleaner_StartCleanup again for the same runaway event, * it should be a noop, therefore requiring no "will_be_called" setup */ RunawayCleaner_StartCleanup(); }