/* * XLogArchiveIsBusy * * Check to see if an XLOG segment file is still unarchived. * This is almost but not quite the inverse of XLogArchiveCheckDone: in * the first place we aren't chartered to recreate the .ready file, and * in the second place we should consider that if the file is already gone * then it's not busy. (This check is needed to handle the race condition * that a checkpoint already deleted the no-longer-needed file.) */ bool XLogArchiveIsBusy(const char *xlog) { char archiveStatusPath[MAXPGPATH]; struct stat stat_buf; /* First check for .done --- this means archiver is done with it */ StatusFilePath(archiveStatusPath, xlog, ".done"); if (stat(archiveStatusPath, &stat_buf) == 0) return false; /* check for .ready --- this means archiver is still busy with it */ StatusFilePath(archiveStatusPath, xlog, ".ready"); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* Race condition --- maybe archiver just finished, so recheck */ StatusFilePath(archiveStatusPath, xlog, ".done"); if (stat(archiveStatusPath, &stat_buf) == 0) return false; /* * Check to see if the WAL file has been removed by checkpoint, which * implies it has already been archived, and explains why we can't see a * status file for it. */ snprintf(archiveStatusPath, MAXPGPATH, XLOGDIR "/%s", xlog); if (stat(archiveStatusPath, &stat_buf) != 0 && errno == ENOENT) return false; return true; }
/* * 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_archiveDone * * Emit notification that an xlog file has been successfully archived. * We do this by renaming the status file from NNN.ready to NNN.done. * Eventually, a checkpoint process will notice this and delete both the * NNN.done file and the xlog file itself. */ static void pgarch_archiveDone(char *xlog) { char rlogready[MAXPGPATH]; char rlogdone[MAXPGPATH]; StatusFilePath(rlogready, xlog, ".ready"); StatusFilePath(rlogdone, xlog, ".done"); if (rename(rlogready, rlogdone) < 0) ereport(WARNING, (errcode_for_file_access(), errmsg("could not rename file \"%s\" to \"%s\": %m", rlogready, rlogdone))); }
/* * XLogArchiveCleanup * * Cleanup archive notification file(s) for a particular xlog segment */ void XLogArchiveCleanup(const char *xlog) { char archiveStatusPath[MAXPGPATH]; /* Remove the .done file */ StatusFilePath(archiveStatusPath, xlog, ".done"); unlink(archiveStatusPath); /* should we complain about failure? */ /* Remove the .ready file if present --- normally it shouldn't be */ StatusFilePath(archiveStatusPath, xlog, ".ready"); unlink(archiveStatusPath); /* should we complain about failure? */ }
/* * XLogArchiveNotify * * Create an archive notification file * * The name of the notification file is the message that will be picked up * by the archiver, e.g. we write 0000000100000001000000C6.ready * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6, * then when complete, rename it to 0000000100000001000000C6.done */ void XLogArchiveNotify(const char *xlog) { char archiveStatusPath[MAXPGPATH]; FILE *fd; /* insert an otherwise empty file called <XLOG>.ready */ StatusFilePath(archiveStatusPath, xlog, ".ready"); fd = AllocateFile(archiveStatusPath, "w"); if (fd == NULL) { ereport(LOG, (errcode_for_file_access(), errmsg("could not create archive status file \"%s\": %m", archiveStatusPath))); return; } if (FreeFile(fd)) { ereport(LOG, (errcode_for_file_access(), errmsg("could not write archive status file \"%s\": %m", archiveStatusPath))); return; } /* Notify archiver that it's got something to do */ if (IsUnderPostmaster) SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER); }
/* * XLogArchiveForceDone * * Emit notification forcibly that an XLOG segment file has been successfully * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready * exists or not. */ void XLogArchiveForceDone(const char *xlog) { char archiveReady[MAXPGPATH]; char archiveDone[MAXPGPATH]; struct stat stat_buf; FILE *fd; /* Exit if already known done */ StatusFilePath(archiveDone, xlog, ".done"); if (stat(archiveDone, &stat_buf) == 0) return; /* If .ready exists, rename it to .done */ StatusFilePath(archiveReady, xlog, ".ready"); if (stat(archiveReady, &stat_buf) == 0) { if (rename(archiveReady, archiveDone) < 0) ereport(WARNING, (errcode_for_file_access(), errmsg("could not rename file \"%s\" to \"%s\": %m", archiveReady, archiveDone))); return; } /* insert an otherwise empty file called <XLOG>.done */ fd = AllocateFile(archiveDone, "w"); if (fd == NULL) { ereport(LOG, (errcode_for_file_access(), errmsg("could not create archive status file \"%s\": %m", archiveDone))); return; } if (FreeFile(fd)) { ereport(LOG, (errcode_for_file_access(), errmsg("could not write archive status file \"%s\": %m", archiveDone))); return; } }
/* * XLogArchiveIsReady * * Check to see if an XLOG segment file has an archive notification (.ready) * file. */ bool XLogArchiveIsReady(const char *xlog) { char archiveStatusPath[MAXPGPATH]; struct stat stat_buf; StatusFilePath(archiveStatusPath, xlog, ".ready"); if (stat(archiveStatusPath, &stat_buf) == 0) return true; return false; }
/* * XLogArchiveIsReadyOrDone * * Check to see if an XLOG segment file has a .ready or .done file. * This is similar to XLogArchiveIsBusy(), but returns true if the file * is already archived or is about to be archived. * * This is currently only used at recovery. During normal operation this * would be racy: the file might get removed or marked with .ready as we're * checking it, or immediately after we return. */ bool XLogArchiveIsReadyOrDone(const char *xlog) { char archiveStatusPath[MAXPGPATH]; struct stat stat_buf; /* 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 true; /* Race condition --- maybe archiver just finished, so recheck */ StatusFilePath(archiveStatusPath, xlog, ".done"); if (stat(archiveStatusPath, &stat_buf) == 0) return true; return false; }