/* * XLogArchiveCheckDone * * This is called when we are ready to delete or recycle an old XLOG segment * file or backup history file. If it is okay to delete it then return true. * If it is not time to delete it, make sure a .ready file exists, and return * false. * * If <XLOG>.done exists, then return true; else if <XLOG>.ready exists, * then return false; else create <XLOG>.ready and return false. * * The reason we do things this way is so that if the original attempt to * create <XLOG>.ready fails, we'll retry during subsequent checkpoints. */ bool XLogArchiveCheckDone(const char *xlog) { char archiveStatusPath[MAXPGPATH]; struct stat stat_buf; /* Always deletable if archiving is off */ if (!XLogArchivingActive()) return true; /* First check for .done --- this means archiver is done with it */ StatusFilePath(archiveStatusPath, xlog, ".done"); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* check for .ready --- this means archiver is still busy with it */ StatusFilePath(archiveStatusPath, xlog, ".ready"); if (stat(archiveStatusPath, &stat_buf) == 0) return false; /* Race condition --- maybe archiver just finished, so recheck */ StatusFilePath(archiveStatusPath, xlog, ".done"); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* Retry creation of the .ready file */ XLogArchiveNotify(xlog); return false; }
/* * pgarch_start * * Called from postmaster at startup or after an existing archiver * died. Attempt to fire up a fresh archiver process. * * Returns PID of child process, or 0 if fail. * * Note: if fail, we will be called again from the postmaster main loop. */ int pgarch_start(void) { time_t curtime; pid_t pgArchPid; /* * Do nothing if no archiver needed */ if (!XLogArchivingActive()) return 0; /* * Do nothing if too soon since last archiver start. This is a safety * valve to protect against continuous respawn attempts if the archiver is * dying immediately at launch. Note that since we will be re-called from * the postmaster main loop, we will get another chance later. */ curtime = time(NULL); if ((unsigned int) (curtime - last_pgarch_start_time) < (unsigned int) PGARCH_RESTART_INTERVAL) return 0; last_pgarch_start_time = curtime; #ifdef EXEC_BACKEND switch ((pgArchPid = pgarch_forkexec())) #else switch ((pgArchPid = fork_process())) #endif { case -1: ereport(LOG, (errmsg("could not fork archiver: %m"))); return 0; #ifndef EXEC_BACKEND case 0: /* in postmaster child ... */ /* Close the postmaster's sockets */ ClosePostmasterPorts(false); /* Lose the postmaster's on-exit routines */ on_exit_reset(); /* Drop our connection to postmaster's shared memory, as well */ PGSharedMemoryDetach(); PgArchiverMain(0, NULL); break; #endif default: return (int) pgArchPid; } /* shouldn't get here */ return 0; }
/* * pgarch_MainLoop * * Main loop for archiver */ static void pgarch_MainLoop(void) { time_t last_copy_time = 0; /* * We run the copy loop immediately upon entry, in case there are * unarchived files left over from a previous database run (or maybe the * archiver died unexpectedly). After that we wait for a signal or * timeout before doing more. */ wakened = true; do { /* Check for config update */ if (got_SIGHUP) { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); if (!XLogArchivingActive()) break; /* user wants us to shut down */ } /* Do what we're here for */ if (wakened) { wakened = false; pgarch_ArchiverCopyLoop(); last_copy_time = time(NULL); } /* * There shouldn't be anything for the archiver to do except to wait * for a signal ... however, the archiver exists to protect our data, * so she wakes up occasionally to allow herself to be proactive. * * On some platforms, signals won't interrupt the sleep. To ensure we * respond reasonably promptly when someone signals us, break down the * sleep into 1-second increments, and check for interrupts after each * nap. */ while (!(wakened || got_SIGHUP)) { time_t curtime; pg_usleep(1000000L); curtime = time(NULL); if ((unsigned int) (curtime - last_copy_time) >= (unsigned int) PGARCH_AUTOWAKE_INTERVAL) wakened = true; } } while (PostmasterIsAlive(true)); }
inline void body() { /* * We run the copy loop immediately upon entry, in case there are * unarchived files left over from a previous database run (or maybe * the archiver died unexpectedly). After that we wait for a signal * or timeout before doing more. */ wakend = true; while(1) { /* Check for config update */ if (got_SIGHUP>0) { got_SIGHUP = 0; ProcessConfigFile(PGC_SIGHUP); __rho_3_ = XLogArchivingActive(); // assume(__rho_3_>0); int tt = __rho_3_; if (tt<=0) break; /* user wants us to shut down */ } /* Do what we're here for */ if (wakend>0) { wakend = 0; pgarch_ArchiverCopyLoop(); __rho_4_ = time(NULL); last_copy_time = __rho_4_; } /* * There shouldn't be anything for the archiver to do except to * wait for a signal, ... however, the archiver exists to * protect our data, so she wakes up occasionally to allow * herself to be proactive. In particular this avoids getting * stuck if a signal arrives just before we sleep. */ if (wakend<=0) { //pg_usleep(PGARCH_AUTOWAKE_INTERVAL * 1000000L); curtime = time(NULL); if ((curtime - last_copy_time) >= PGARCH_AUTOWAKE_INTERVAL) wakend = true; } __rho_5_ = PostmasterIsAlive(true); dummy = __rho_5_; if (dummy<=0) break; } while(1) { dummy=dummy; } L_return: return 0; }
/* * pgarch_MainLoop * * Main loop for archiver */ static void pgarch_MainLoop(void) { time_t last_copy_time = 0; time_t curtime; /* * We run the copy loop immediately upon entry, in case there are * unarchived files left over from a previous database run (or maybe the * archiver died unexpectedly). After that we wait for a signal or * timeout before doing more. */ wakened = true; do { /* Check for config update */ if (got_SIGHUP) { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); if (!XLogArchivingActive()) break; /* user wants us to shut down */ } /* Do what we're here for */ if (wakened) { wakened = false; pgarch_ArchiverCopyLoop(); last_copy_time = time(NULL); } /* * There shouldn't be anything for the archiver to do except to wait * for a signal, ... however, the archiver exists to protect our data, * so she wakes up occasionally to allow herself to be proactive. In * particular this avoids getting stuck if a signal arrives just * before we sleep. */ if (!wakened) { pg_usleep(PGARCH_AUTOWAKE_INTERVAL * 1000000L); curtime = time(NULL); if ((unsigned int) (curtime - last_copy_time) >= (unsigned int) PGARCH_AUTOWAKE_INTERVAL) wakened = true; } } while (PostmasterIsAlive(true)); }
static void _bt_mergebuild(Spooler *self, BTSpool *btspool) { Relation heapRel = self->relinfo->ri_RelationDesc; BTWriteState wstate; BTReader reader; bool merge; Assert(btspool->index->rd_index->indisvalid); tuplesort_performsort(btspool->sortstate); wstate.index = btspool->index; /* * We need to log index creation in WAL iff WAL archiving is enabled AND * it's not a temp index. */ wstate.btws_use_wal = self->use_wal && XLogArchivingActive() && !RELATION_IS_LOCAL(wstate.index); /* reserve the metapage */ wstate.btws_pages_alloced = BTREE_METAPAGE + 1; wstate.btws_pages_written = 0; wstate.btws_zeropage = NULL; /* until needed */ /* * Flush dirty buffers so that we will read the index files directly * in order to get pre-existing data. We must acquire AccessExclusiveLock * for the target table for calling FlushRelationBuffer(). */ LockRelation(wstate.index, AccessExclusiveLock); FlushRelationBuffers(wstate.index); BULKLOAD_PROFILE(&prof_flush); merge = BTReaderInit(&reader, wstate.index); elog(DEBUG1, "pg_bulkload: build \"%s\" %s merge (%s wal)", RelationGetRelationName(wstate.index), merge ? "with" : "without", wstate.btws_use_wal ? "with" : "without"); /* Assign a new file node. */ RelationSetNewRelfilenode(wstate.index, InvalidTransactionId); if (merge || (btspool->isunique && self->max_dup_errors > 0)) { /* Merge two streams into the new file node that we assigned. */ BULKLOAD_PROFILE_PUSH(); _bt_mergeload(self, &wstate, btspool, &reader, heapRel); BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE(&prof_merge); } else { /* Fast path for newly created index. */ _bt_load(&wstate, btspool, NULL); BULKLOAD_PROFILE(&prof_index); } BTReaderTerm(&reader); }