From 9378701243b5a9075a5c0e11909cb3eec7428801 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 24 Dec 2018 20:26:11 +0900 Subject: [PATCH] Prioritize history files when archiving At the end of recovery for the post-promotion process, a new history file is created followed by the last partial segment of the previous timeline. Based on the timing, the archiver would first try to archive the last partial segment and then the history file. This can delay the detection of a new timeline taken, particularly depending on the time it takes to transfer the last partial segment as it delays the moment the history file of the new timeline gets archived. This can cause promoted standbys to use the same timeline as one already taken depending on the circumstances if multiple instances look at archives at the same location. This commit changes the order of archiving so as history files are archived in priority over other file types, which reduces the likelihood of the same timeline being taken (still not reducing the window to zero), and it makes the archiver behave more consistently with the startup process doing its post-promotion business. Author: David Steele Reviewed-by: Michael Paquier, Kyotaro Horiguchi Discussion: https://postgr.es/m/929068cf-69e1-bba2-9dc0-e05986aed471@pgmasters.net Backpatch-through: 9.5 --- src/backend/postmaster/pgarch.c | 72 +++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index 1aa6466d67..14350fb7de 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -651,11 +651,12 @@ pgarch_archiveXlog(char *xlog) * 2) because the oldest ones will sooner become candidates for * recycling at time of checkpoint * - * NOTE: the "oldest" comparison will presently consider all segments of - * a timeline with a smaller ID to be older than all segments of a timeline - * with a larger ID; the net result being that past timelines are given - * higher priority for archiving. This seems okay, or at least not - * obviously worth changing. + * NOTE: the "oldest" comparison will consider any .history file to be older + * than any other file except another .history file. Segments on a timeline + * with a smaller ID will be older than all segments on a timeline with a + * larger ID; the net result being that past timelines are given higher + * priority for archiving. This seems okay, or at least not obviously worth + * changing. */ static bool pgarch_readyXlog(char *xlog) @@ -667,10 +668,10 @@ pgarch_readyXlog(char *xlog) * of calls, so.... */ char XLogArchiveStatusDir[MAXPGPATH]; - char newxlog[MAX_XFN_CHARS + 6 + 1]; DIR *rldir; struct dirent *rlde; bool found = false; + bool historyFound = false; snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status"); rldir = AllocateDir(XLogArchiveStatusDir); @@ -683,32 +684,51 @@ pgarch_readyXlog(char *xlog) while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL) { int basenamelen = (int) strlen(rlde->d_name) - 6; + char basename[MAX_XFN_CHARS + 1]; + bool ishistory; - if (basenamelen >= MIN_XFN_CHARS && - basenamelen <= MAX_XFN_CHARS && - strspn(rlde->d_name, VALID_XFN_CHARS) >= basenamelen && - strcmp(rlde->d_name + basenamelen, ".ready") == 0) + /* Ignore entries with unexpected number of characters */ + if (basenamelen < MIN_XFN_CHARS || + basenamelen > MAX_XFN_CHARS) + continue; + + /* Ignore entries with unexpected characters */ + if (strspn(rlde->d_name, VALID_XFN_CHARS) < basenamelen) + continue; + + /* Ignore anything not suffixed with .ready */ + if (strcmp(rlde->d_name + basenamelen, ".ready") != 0) + continue; + + /* Truncate off the .ready */ + memcpy(basename, rlde->d_name, basenamelen); + basename[basenamelen] = '\0'; + + /* Is this a history file? */ + ishistory = IsTLHistoryFileName(basename); + + /* + * Consume the file to archive. History files have the highest + * priority. If this is the first file or the first history file + * ever, copy it. In the presence of a history file already chosen as + * target, ignore all other files except history files which have been + * generated for an older timeline than what is already chosen as + * target to archive. + */ + if (!found || (ishistory && !historyFound)) { - if (!found) - { - strcpy(newxlog, rlde->d_name); - found = true; - } - else - { - if (strcmp(rlde->d_name, newxlog) < 0) - strcpy(newxlog, rlde->d_name); - } + strcpy(xlog, basename); + found = true; + historyFound = ishistory; + } + else if (ishistory || !historyFound) + { + if (strcmp(basename, xlog) < 0) + strcpy(xlog, basename); } } FreeDir(rldir); - if (found) - { - /* truncate off the .ready */ - newxlog[strlen(newxlog) - 6] = '\0'; - strcpy(xlog, newxlog); - } return found; } -- 2.40.0