/* * Backend-shutdown callback. Do cleanup that we want to be sure happens * before all the supporting modules begin to nail their doors shut via * their own callbacks. * * User-level cleanup, such as temp-relation removal and UNLISTEN, happens * via separate callbacks that execute before this one. We don't combine the * callbacks because we still want this one to happen if the user-level * cleanup fails. */ static void ShutdownPostgres(int code, Datum arg) { /* Make sure we've killed any active transaction */ AbortOutOfAnyTransaction(); /* * User locks are not released by transaction end, so be sure to release * them explicitly. */ LockReleaseAll(USER_LOCKMETHOD, true); }
static void DiscardAll(bool isTopLevel) { /* * Disallow DISCARD ALL in a transaction block. This is arguably * inconsistent (we don't make a similar check in the command sequence * that DISCARD ALL is equivalent to), but the idea is to catch mistakes: * DISCARD ALL inside a transaction block would leave the transaction * still uncommitted. */ PreventTransactionChain(isTopLevel, "DISCARD ALL"); SetPGVariable("session_authorization", NIL, false); ResetAllOptions(); DropAllPreparedStatements(); PortalHashTableDeleteAll(); Async_UnlistenAll(); LockReleaseAll(USER_LOCKMETHOD, true); ResetPlanCache(); ResetTempTableNamespace(); }
/* * Backend-shutdown callback. Do cleanup that we want to be sure happens * before all the supporting modules begin to nail their doors shut via * their own callbacks. * * User-level cleanup, such as temp-relation removal and UNLISTEN, happens * via separate callbacks that execute before this one. We don't combine the * callbacks because we still want this one to happen if the user-level * cleanup fails. */ static void ShutdownPostgres(int code, Datum arg) { /* Make sure we've killed any active transaction */ AbortOutOfAnyTransaction(); /* * If there was a segment OOM for which we haven't already reported * our usage, report now. */ ReportOOMConsumption(); /* Disable memory protection */ GPMemoryProtect_Shutdown(); /* Release SessionState entry */ SessionState_Shutdown(); /* * User locks are not released by transaction end, so be sure to release * them explicitly. */ LockReleaseAll(USER_LOCKMETHOD, true); }
void FileRepSubProcess_Main() { const char *statmsg; MemoryContext fileRepSubProcessMemoryContext; sigjmp_buf local_sigjmp_buf; MyProcPid = getpid(); MyStartTime = time(NULL); /* * Create a PGPROC so we can use LWLocks in FileRep sub-processes. The * routine also register clean up at process exit */ InitAuxiliaryProcess(); InitBufferPoolBackend(); FileRepSubProcess_ConfigureSignals(); /* * If an exception is encountered, processing resumes here. * * See notes in postgres.c about the design of this coding. */ if (sigsetjmp(local_sigjmp_buf, 1) != 0) { /* Prevents interrupts while cleaning up */ HOLD_INTERRUPTS(); /* Report the error to the server log */ EmitErrorReport(); LWLockReleaseAll(); if (FileRepPrimary_IsResyncManagerOrWorker()) { LockReleaseAll(DEFAULT_LOCKMETHOD, false); } if (FileRepIsBackendSubProcess(fileRepProcessType)) { AbortBufferIO(); UnlockBuffers(); /* buffer pins are released here: */ ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true); } /* * We can now go away. Note that because we'll call InitProcess, a * callback will be registered to do ProcKill, which will clean up * necessary state. */ proc_exit(0); } /* We can now handle ereport(ERROR) */ PG_exception_stack = &local_sigjmp_buf; PG_SETMASK(&UnBlockSig); /* * Identify myself via ps */ statmsg = FileRepProcessTypeToString[fileRepProcessType]; init_ps_display(statmsg, "", "", ""); /* Create the memory context where cross-transaction state is stored */ fileRepSubProcessMemoryContext = AllocSetContextCreate(TopMemoryContext, "filerep subprocess memory context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(fileRepSubProcessMemoryContext); stateChangeRequestCounter++; FileRepSubProcess_ProcessSignals(); switch (fileRepProcessType) { case FileRepProcessTypePrimarySender: FileRepPrimary_StartSender(); break; case FileRepProcessTypeMirrorReceiver: FileRepMirror_StartReceiver(); break; case FileRepProcessTypeMirrorConsumer: case FileRepProcessTypeMirrorConsumerWriter: case FileRepProcessTypeMirrorConsumerAppendOnly1: FileRepMirror_StartConsumer(); break; case FileRepProcessTypeMirrorSenderAck: FileRepAckMirror_StartSender(); break; case FileRepProcessTypePrimaryReceiverAck: FileRepAckPrimary_StartReceiver(); break; case FileRepProcessTypePrimaryConsumerAck: FileRepAckPrimary_StartConsumer(); break; case FileRepProcessTypePrimaryRecovery: FileRepSubProcess_InitProcess(); /* * At this point, database is starting up and xlog is not yet * replayed. Initializing relcache now is dangerous, a sequential * scan of catalog tables may end up with incorrect hint bits. * E.g. a committed transaction's dirty heap pages made it to disk * but pg_clog update was still in memory and we crashed. If a * tuple inserted by this transaction is read during relcache * initialization, status of the tuple's xmin will be incorrectly * determined as "not commited" from pg_clog. And * HEAP_XMIN_INVALID hint bit will be set, rendering the tuple * perpetually invisible. Relcache initialization must be * deferred to only after all of xlog has been replayed. */ FileRepPrimary_StartRecovery(); ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true); break; case FileRepProcessTypeResyncManager: FileRepSubProcess_InitProcess(); FileRepPrimary_StartResyncManager(); ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true); break; case FileRepProcessTypeResyncWorker1: case FileRepProcessTypeResyncWorker2: case FileRepProcessTypeResyncWorker3: case FileRepProcessTypeResyncWorker4: FileRepSubProcess_InitProcess(); FileRepPrimary_StartResyncWorker(); ResourceOwnerRelease(CurrentResourceOwner, RESOURCE_RELEASE_BEFORE_LOCKS, false, true); break; default: elog(PANIC, "unrecognized process type: %s(%d)", statmsg, fileRepProcessType); break; } switch (FileRepSubProcess_GetState()) { case FileRepStateShutdown: case FileRepStateReady: proc_exit(0); break; default: proc_exit(2); break; } }
/* * SIGUSR2 signal from main file rep process */ static void FileRepSubProcess_ShutdownHandler(SIGNAL_ARGS) { bool isInTransition = FALSE; DataState_e dataStateTransition; shutdownRequested = true; /* * Exit the process if recv() call is hanging or compacting is running. * Compacting can take many minutes. */ if (fileRepProcessType == FileRepProcessTypePrimaryReceiverAck || fileRepProcessType == FileRepProcessTypeMirrorReceiver || fileRepProcessType == FileRepProcessTypePrimaryRecovery) { /* workaround for gcov testing */ if (Debug_filerep_gcov) { getFileRepRoleAndState(&fileRepRole, &segmentState, &dataState, &isInTransition, &dataStateTransition); if (isInTransition == TRUE && dataStateTransition == DataStateInChangeTracking) { proc_exit(0); return; } } die(PASS_SIGNAL_ARGS); } if (FileRepIsBackendSubProcess(fileRepProcessType)) { if (FileRepPrimary_IsResyncManagerOrWorker()) { getFileRepRoleAndState(&fileRepRole, &segmentState, &dataState, &isInTransition, &dataStateTransition); if (isInTransition == TRUE && dataStateTransition == DataStateInChangeTracking) { /* * Resync workers and manager may be waiting on lock that is * acquired by backend process that is suspended during * transition to Change Tracking and so FileRep backend * shutdown may never be completed. */ if (fileRepProcessType == FileRepProcessTypeResyncManager) { FileRepResync_Cleanup(); } else { LockReleaseAll(DEFAULT_LOCKMETHOD, false); } /* * We remove ourself from LW waiter list (if applicable). * * If the current backend is waiting on a LWLock and exits w/o * any cleanup (remove from waiters list) it can cause a * breakage in the LWlock's waiters linked list after it dies. * This can lead to unpleasant issues causing starvation for * subsequent waiters because the current backend is already * dead without assigning the LWLock to the next waiter. * * XXX Side note - Although implemented here, avoid exiting * inside an signal handler. */ LWLockWaitCancel(); LWLockReleaseAll(); proc_exit(0); return; } } /* * call the normal postgres die so that it requests query * cancel/procdie */ die(PASS_SIGNAL_ARGS); } }