/* These fields are valid if workerStatus == WRKR_WORKING: */
ParallelCompletionPtr callback; /* function to call on completion */ void *callback_data; /* passthrough data for it */
ArchiveHandle *AH; /* Archive data worker is using */
int pipeRead; /* leader's end of the pipes */ int pipeWrite; int pipeRevRead; /* child's end of the pipes */ int pipeRevWrite;
/* *Stateinfoforsignalhandling. *Weassumesignal_infoinitializestozeroes. * *OnUnix,myAHistheleaderDBconnectionintheleaderprocess,andthe *worker'sownconnectioninworkerprocesses.OnWindows,wehaveonlyone *instanceofsignal_info,somyAHistheleaderconnectionandtheworker *connectionsmustbedugoutofpstate->parallelSlot[].
*/ typedefstruct DumpSignalInformation
{
ArchiveHandle *myAH; /* database connection to issue cancel for */
ParallelState *pstate; /* parallel state, if any */ bool handler_set; /* signal handler set up in this process? */ #ifndef WIN32 bool am_worker; /* am I a worker process? */ #endif
} DumpSignalInformation;
for (i = 0; i < pstate->numWorkers; i++)
{ #ifdef WIN32 if (pstate->parallelSlot[i].threadId == GetCurrentThreadId()) #else if (pstate->parallelSlot[i].pid == getpid()) #endif return &(pstate->parallelSlot[i]);
}
if (parallel_init_done)
id_return = (PQExpBuffer) TlsGetValue(tls_index); else
id_return = s_id_return;
if (id_return) /* first time through? */
{ /* same buffer, just wipe contents */
resetPQExpBuffer(id_return);
} else
{ /* new buffer */
id_return = createPQExpBuffer(); if (parallel_init_done)
TlsSetValue(tls_index, id_return); else
s_id_return = id_return;
}
/* *Closeourwriteendofthesocketssothatanyworkerswaitingfor *commandsknowtheycanexit.(Note:someofthepipeWritefieldsmight *stillbezero,ifwefailedtoinitializealltheworkers.Hence,just *ignoreerrorshere.)
*/ for (i = 0; i < pstate->numWorkers; i++)
closesocket(pstate->parallelSlot[i].pipeWrite);
/* *Forceearlyterminationofanycommandscurrentlyinprogress.
*/ #ifndef WIN32 /* On non-Windows, send SIGTERM to each worker process. */ for (i = 0; i < pstate->numWorkers; i++)
{
pid_t pid = pstate->parallelSlot[i].pid;
if (pid != 0)
kill(pid, SIGTERM);
} #else
/* *OnWindows,sendquerycancelsdirectlytotheworkers'backends.Use *acriticalsectiontoensureworkerthreadsdon'tchangestate.
*/
EnterCriticalSection(&signal_info_lock); for (i = 0; i < pstate->numWorkers; i++)
{
ArchiveHandle *AH = pstate->parallelSlot[i].AH; char errbuf[1];
/* Find dead worker's slot, and clear the hThread field */ for (j = 0; j < pstate->numWorkers; j++)
{
slot = &(pstate->parallelSlot[j]); if (slot->hThread == hThread)
{ /* For cleanliness, close handles for dead threads */
CloseHandle((HANDLE) slot->hThread);
slot->hThread = (uintptr_t) INVALID_HANDLE_VALUE; break;
}
} #endif/* WIN32 */
/* On all platforms, update workerStatus and te[] as well */
Assert(j < pstate->numWorkers);
slot->workerStatus = WRKR_TERMINATED;
pstate->te[j] = NULL;
}
}
if (dwCtrlType == CTRL_C_EVENT ||
dwCtrlType == CTRL_BREAK_EVENT)
{ /* Critical section prevents changing data we look at here */
EnterCriticalSection(&signal_info_lock);
/* *Ifinparallelmode,stopworkerthreadsandsendQueryCancelto *theirconnectedbackends.Themainpointofstoppingtheworker *threadsistokeepthemfromreportingthequerycancelsaserrors, *whichwouldcluttertheuser'sscreen.Weneedn'tstoptheleader *threadsinceitwon'tbedoingmuchanyway.Dothisbefore *cancelingthemaintransaction,elsewemightgetinvalid-snapshot *errorsreportedbeforewecanstoptheworkers.Ignoreerrors, *there'snotmuchwecandoaboutthemanyway.
*/ if (signal_info.pstate != NULL)
{ for (i = 0; i < signal_info.pstate->numWorkers; i++)
{
ParallelSlot *slot = &(signal_info.pstate->parallelSlot[i]);
ArchiveHandle *AH = slot->AH;
HANDLE hThread = (HANDLE) slot->hThread;
/* Free the old one if we have one */
oldConnCancel = AH->connCancel; /* be sure interrupt handler doesn't use pointer while freeing */
AH->connCancel = NULL;
if (oldConnCancel != NULL)
PQfreeCancel(oldConnCancel);
/* Set the new one if specified */ if (conn)
AH->connCancel = PQgetCancel(conn);
/* Ensure stdio state is quiesced before forking */
fflush(NULL);
/* Create desired number of workers */ for (i = 0; i < pstate->numWorkers; i++)
{ #ifdef WIN32
WorkerInfo *wi;
uintptr_t handle; #else
pid_t pid; #endif
ParallelSlot *slot = &(pstate->parallelSlot[i]); int pipeMW[2],
pipeWM[2];
/* Create communication pipes for this worker */ if (pgpipe(pipeMW) < 0 || pgpipe(pipeWM) < 0)
pg_fatal("could not create communication channels: %m");
/* leader's ends of the pipes */
slot->pipeRead = pipeWM[PIPE_READ];
slot->pipeWrite = pipeMW[PIPE_WRITE]; /* child's ends of the pipes */
slot->pipeRevRead = pipeMW[PIPE_READ];
slot->pipeRevWrite = pipeWM[PIPE_WRITE];
#ifdef WIN32 /* Create transient structure to pass args to worker function */
wi = (WorkerInfo *) pg_malloc(sizeof(WorkerInfo));
wi->AH = AH;
wi->slot = slot;
handle = _beginthreadex(NULL, 0, (void *) &init_spawned_worker_win32,
wi, 0, &(slot->threadId));
slot->hThread = handle;
slot->workerStatus = WRKR_IDLE; #else/* !WIN32 */
pid = fork(); if (pid == 0)
{ /* we are the worker */ int j;
/* this is needed for GetMyPSlot() */
slot->pid = getpid();
/* instruct signal handler that we're in a worker now */
signal_info.am_worker = true;
/* close read end of Worker -> Leader */
closesocket(pipeWM[PIPE_READ]); /* close write end of Leader -> Worker */
closesocket(pipeMW[PIPE_WRITE]);
/* We can just exit(0) when done */ exit(0);
} elseif (pid < 0)
{ /* fork failed */
pg_fatal("could not create worker process: %m");
}
/* In Leader after successful fork */
slot->pid = pid;
slot->workerStatus = WRKR_IDLE;
/* close read end of Leader -> Worker */
closesocket(pipeMW[PIPE_READ]); /* close write end of Worker -> Leader */
closesocket(pipeWM[PIPE_WRITE]); #endif/* WIN32 */
}
/* No work if non-parallel */ if (pstate->numWorkers == 1) return;
/* There should not be any unfinished jobs */
Assert(IsEveryWorkerIdle(pstate));
/* Close the sockets so that the workers know they can exit */ for (i = 0; i < pstate->numWorkers; i++)
{
closesocket(pstate->parallelSlot[i].pipeRead);
closesocket(pstate->parallelSlot[i].pipeWrite);
}
/* Wait for them to exit */
WaitForTerminatingWorkers(pstate);
/* Remember worker is busy, and which TocEntry it's working on */
pstate->parallelSlot[worker].workerStatus = WRKR_WORKING;
pstate->parallelSlot[worker].callback = callback;
pstate->parallelSlot[worker].callback_data = callback_data;
pstate->te[worker] = te;
}
/* *Findanidleworkerandreturnitsslotnumber. *ReturnNO_SLOTifnoneareidle.
*/ staticint
GetIdleWorker(ParallelState *pstate)
{ int i;
for (i = 0; i < pstate->numWorkers; i++)
{ if (pstate->parallelSlot[i].workerStatus == WRKR_IDLE) return i;
} return NO_SLOT;
}
/* *Returntrueiffnoworkerisrunning.
*/ staticbool
HasEveryWorkerTerminated(ParallelState *pstate)
{ int i;
for (i = 0; i < pstate->numWorkers; i++)
{ if (WORKER_IS_RUNNING(pstate->parallelSlot[i].workerStatus)) returnfalse;
} returntrue;
}
/* *ReturntrueiffeveryworkerisintheWRKR_IDLEstate.
*/ bool
IsEveryWorkerIdle(ParallelState *pstate)
{ int i;
for (i = 0; i < pstate->numWorkers; i++)
{ if (pstate->parallelSlot[i].workerStatus != WRKR_IDLE) returnfalse;
} returntrue;
}
/* Nothing to do for BLOBS */ if (strcmp(te->desc, "BLOBS") == 0) return;
query = createPQExpBuffer();
qualId = fmtQualifiedId(te->namespace, te->tag);
appendPQExpBuffer(query, "LOCK TABLE %s IN ACCESS SHARE MODE NOWAIT",
qualId);
res = PQexec(AH->connection, query->data);
if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
pg_fatal("could not obtain lock on relation \"%s\"\n" "This usually means that someone requested an ACCESS EXCLUSIVE lock " "on the table after the pg_dump parent process had gotten the " "initial ACCESS SHARE lock on the table.", qualId);
PQclear(res);
destroyPQExpBuffer(query);
}
/* *WaitForCommands:mainroutineforaworkerprocess. * *ReadandexecutecommandsfromtheleaderuntilweseeEOFonthepipe.
*/ staticvoid
WaitForCommands(ArchiveHandle *AH, int pipefd[2])
{ char *command;
TocEntry *te;
T_Action act; int status = 0; char buf[256];
for (;;)
{ if (!(command = getMessageFromLeader(pipefd)))
{ /* EOF, so done */ return;
}
/* Decode the command */
parseWorkerCommand(AH, &te, &act, command);
if (act == ACT_DUMP)
{ /* Acquire lock on this table within the worker's session */
lockTableForWorker(AH, te);
/* Perform the dump command */
status = (AH->WorkerJobDumpPtr) (AH, te);
} elseif (act == ACT_RESTORE)
{ /* Perform the restore command */
status = (AH->WorkerJobRestorePtr) (AH, te);
} else
Assert(false);
/* Return status to leader */
buildWorkerResponse(AH, te, act, status, buf, sizeof(buf));
sendMessageToLeader(pipefd, buf);
/* command was pg_malloc'd and we are responsible for free()ing it. */
free(command);
}
}
/* Try to collect a status message */
msg = getMessageFromWorker(pstate, do_wait, &worker);
if (!msg)
{ /* If do_wait is true, we must have detected EOF on some socket */ if (do_wait)
pg_fatal("a worker process died unexpectedly"); returnfalse;
}
/* Process it and update our idea of the worker's status */ if (messageStartsWith(msg, "OK "))
{
ParallelSlot *slot = &pstate->parallelSlot[worker];
TocEntry *te = pstate->te[worker]; int status;
status = parseWorkerResponse(AH, te, msg);
slot->callback(AH, te, status, slot->callback_data);
slot->workerStatus = WRKR_IDLE;
pstate->te[worker] = NULL;
} else
pg_fatal("invalid message received from worker: \"%s\"",
msg);
/* Free the string returned from getMessageFromWorker */
free(msg);
/* *InGOT_STATUSmode,alwaysblockwaitingforamessage,sincewecan't *returntillwegetsomething.Inothermodes,wedon'tblockthefirst *timethroughtheloop.
*/ if (mode == WFW_GOT_STATUS)
{ /* Assert that caller knows what it's doing */
Assert(!IsEveryWorkerIdle(pstate));
do_wait = true;
}
for (;;)
{ /* *Checkforstatusmessages,evenifwedon'tneedtoblock.Wedo *nottryveryhardtoreapallavailablemessages,though,since *there'sunlikelytobemorethanone.
*/ if (ListenToWorkers(AH, pstate, do_wait))
{ /* *Ifwegotamessage,wearedonebydefinitionforGOT_STATUS *mode,andwecanalsobecertainthatthere'satleastoneidle *worker.Sowe'redoneinallbutALL_IDLEmode.
*/ if (mode != WFW_ALL_IDLE) return;
}
/* Check whether we must wait for new status messages */ switch (mode)
{ case WFW_NO_WAIT: return; /* never wait */ case WFW_GOT_STATUS:
Assert(false); /* can't get here, because we waited */ break; case WFW_ONE_IDLE: if (GetIdleWorker(pstate) != NO_SLOT) return; break; case WFW_ALL_IDLE: if (IsEveryWorkerIdle(pstate)) return; break;
}
/* Loop back, and this time wait for something to happen */
do_wait = true;
}
}
/* construct bitmap of socket descriptors for select() */
FD_ZERO(&workerset); for (i = 0; i < pstate->numWorkers; i++)
{ if (!WORKER_IS_RUNNING(pstate->parallelSlot[i].workerStatus)) continue;
FD_SET(pstate->parallelSlot[i].pipeRead, &workerset); if (pstate->parallelSlot[i].pipeRead > maxFd)
maxFd = pstate->parallelSlot[i].pipeRead;
}
if (do_wait)
{
i = select_loop(maxFd, &workerset);
Assert(i != 0);
} else
{ if ((i = select(maxFd + 1, &workerset, NULL, NULL, &nowait)) == 0) return NULL;
}
if (i < 0)
pg_fatal("%s() failed: %m", "select");
for (i = 0; i < pstate->numWorkers; i++)
{ char *msg;
if (!WORKER_IS_RUNNING(pstate->parallelSlot[i].workerStatus)) continue; if (!FD_ISSET(pstate->parallelSlot[i].pipeRead, &workerset)) continue;
msgsize++; if (msgsize == bufsize) /* enlarge buffer if needed */
{
bufsize += 16; /* could be any number */
msg = (char *) pg_realloc(msg, bufsize);
}
}
/* Other end has closed the connection */
pg_free(msg); return NULL;
}
/* *setuppipehandles
*/ if ((tmp_sock = socket(AF_INET, SOCK_STREAM, 0)) == PGINVALID_SOCKET)
{
pg_log_error("pgpipe: could not create second socket: error code %d",
WSAGetLastError());
closesocket(s); return -1;
}
handles[1] = (int) tmp_sock;
if (connect(handles[1], (SOCKADDR *) &serv_addr, len) == SOCKET_ERROR)
{
pg_log_error("pgpipe: could not connect socket: error code %d",
WSAGetLastError());
closesocket(handles[1]);
handles[1] = -1;
closesocket(s); return -1;
} if ((tmp_sock = accept(s, (SOCKADDR *) &serv_addr, &len)) == PGINVALID_SOCKET)
{
pg_log_error("pgpipe: could not accept connection: error code %d",
WSAGetLastError());
closesocket(handles[1]);
handles[1] = -1;
closesocket(s); return -1;
}
handles[0] = (int) tmp_sock;
closesocket(s); return0;
}
#endif/* WIN32 */
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.59Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.