/* * Saves VMEM usage of all the sessions into log */ void RedZoneHandler_LogVmemUsageOfAllSessions() { if (!vmemTrackerInited) { return; } Assert(NULL != MySessionState); /* * Grabbing a shared lock ensures that the data structure is not * modified while we are reading. Shared lock is enough as we * are only reading and not modifying the SessionState data structure */ LWLockAcquire(SessionStateLock, LW_SHARED); SessionState *curSessionState = AllSessionStateEntries->usedList; PG_TRY(); { /* Write the header for the subsequent lines of memory usage information */ write_stderr("session_state: session_id, is_runaway, qe_count, active_qe_count, dirty_qe_count, vmem_mb, runaway_vmem_mb, runaway_command_cnt\n"); while (curSessionState != NULL) { Assert(INVALID_SESSION_ID != curSessionState->sessionId); write_stderr("session_state: %d, %d, %d, %d, %d, %d, %d, %d\n", curSessionState->sessionId, curSessionState->runawayStatus != RunawayStatus_NotRunaway, curSessionState->pinCount, curSessionState->activeProcessCount, curSessionState->cleanupCountdown, VmemTracker_ConvertVmemChunksToMB(curSessionState->sessionVmem), VmemTracker_ConvertVmemChunksToMB(curSessionState->sessionVmemRunaway), curSessionState->commandCountRunaway); curSessionState = curSessionState->next; } } PG_CATCH(); { LWLockRelease(SessionStateLock); PG_RE_THROW(); } PG_END_TRY(); LWLockRelease(SessionStateLock); }
/* * Starts a runaway cleanup by triggering an ERROR if the VMEM tracker is active * and a commit is not already in progress. Otherwise, it marks the process as clean */ void RunawayCleaner_StartCleanup() { /* * Cleanup can be attempted from multiple places, such as before deactivating * a process (if a pending runaway event) or periodically from CHECK_FOR_INTERRUPTS * (indirectly via RedZoneHandler_DetectRunaway). We don't carry multiple cleanup * for a single runaway event. Every time we *start* a cleanup process, we set the * beginCleanupRunawayVersion to the runaway version for which we started cleaning * up. Later on, if we reenter this method (e.g., another CHECK_FOR_INTERRUPTS() * during cleanup), we can observe that the cleanup already started from this runaway * event, and therefore we skip duplicate cleanup */ if (RunawayCleaner_ShouldStartRunawayCleanup()) { Assert(beginCleanupRunawayVersion < *latestRunawayVersion); Assert(endCleanupRunawayVersion < *latestRunawayVersion); /* We don't want to cleanup multiple times for same runaway event */ beginCleanupRunawayVersion = *latestRunawayVersion; if (CritSectionCount == 0 && InterruptHoldoffCount == 0 && vmemTrackerInited && gp_command_count > 0 /* Cleaning up QEs that are not executing a valid command may cause the QD to get stuck [MPP-24950] */ && /* Super user is terminated only when it's the primary runaway consumer (i.e., the top consumer) */ (!superuser() || MySessionState->runawayStatus == RunawayStatus_PrimaryRunawaySession)) { #ifdef FAULT_INJECTOR FaultInjector_InjectFaultIfSet( RunawayCleanup, DDLNotSpecified, "", // databaseName ""); // tableName #endif ereport(ERROR, (errmsg("Canceling query because of high VMEM usage. Used: %dMB, available %dMB, red zone: %dMB", VmemTracker_ConvertVmemChunksToMB(MySessionState->sessionVmem), VmemTracker_GetAvailableVmemMB(), RedZoneHandler_GetRedZoneLimitMB()), errprintstack(true))); } /* * If we cannot error out because of a critical section or because we are a super user * or for some other reason (such as the QE is not running any valid command, i.e., * gp_command_count is not positive) simply declare this process as clean */ RunawayCleaner_RunawayCleanupDoneForProcess(true /* ignoredCleanup */); } }
/* * Returns the red-zone cut-off in "MB" unit */ int32 RedZoneHandler_GetRedZoneLimitMB() { return VmemTracker_ConvertVmemChunksToMB(redZoneChunks); }