summaryrefslogtreecommitdiff
path: root/src/backend/storage/smgr/md.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2022-07-28 16:03:42 -0400
committerRobert Haas <rhaas@postgresql.org>2022-07-28 16:03:42 -0400
commitbbe08b8869bd29d587f24ef18eb45c7d4d14afca (patch)
treed4be33aa407e3fdd3cf6de07fee0a14bad5a5450 /src/backend/storage/smgr/md.c
parente09d7a1262c659578065eaf7edafe606d2c8ebf2 (diff)
Use TRUNCATE to preserve relfilenode for pg_largeobject + index.
Commit 9a974cbcba005256a19991203583a94b4f9a21a9 arranged to preserve the relfilenode of user tables across pg_upgrade, but failed to notice that pg_upgrade treats pg_largeobject as a user table and thus it needs the same treatment. Otherwise, large objects will appear to vanish after a pg_upgrade. Commit d498e052b4b84ae21b3b68d5b3fda6ead65d1d4d fixed this problem by teaching pg_dump to UPDATE pg_class.relfilenode for pg_largeobject and its index. However, because an UPDATE on the catalog rows doesn't change anything on disk, this can leave stray files behind in the new cluster. They will normally be empty, but it's a little bit untidy. Hence, this commit arranges to do the same thing using DDL. Specifically, it makes TRUNCATE work for the pg_largeobject catalog when in binary-upgrade mode, and it then uses that command in binary-upgrade dumps as a way of setting pg_class.relfilenode for pg_largeobject and its index. That way, the old files are removed from the new cluster. Discussion: http://postgr.es/m/CA+TgmoYYMXGUJO5GZk1-MByJGu_bB8CbOL6GJQC8=Bzt6x6vDg@mail.gmail.com
Diffstat (limited to 'src/backend/storage/smgr/md.c')
-rw-r--r--src/backend/storage/smgr/md.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 3998296a62f..3deac496eed 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -319,6 +319,7 @@ mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forkNum, bool isRedo)
{
char *path;
int ret;
+ BlockNumber segno = 0;
path = relpath(rlocator, forkNum);
@@ -353,8 +354,22 @@ mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forkNum, bool isRedo)
/* Prevent other backends' fds from holding on to the disk space */
ret = do_truncate(path);
- /* Register request to unlink first segment later */
- register_unlink_segment(rlocator, forkNum, 0 /* first seg */ );
+ /*
+ * Except during a binary upgrade, register request to unlink first
+ * segment later, rather than now.
+ *
+ * If we're performing a binary upgrade, the dangers described in the
+ * header comments for mdunlink() do not exist, since after a crash
+ * or even a simple ERROR, the upgrade fails and the whole new cluster
+ * must be recreated from scratch. And, on the other hand, it is
+ * important to remove the files from disk immediately, because we
+ * may be about to reuse the same relfilenumber.
+ */
+ if (!IsBinaryUpgrade)
+ {
+ register_unlink_segment(rlocator, forkNum, 0 /* first seg */ );
+ ++segno;
+ }
}
/*
@@ -363,15 +378,17 @@ mdunlinkfork(RelFileLocatorBackend rlocator, ForkNumber forkNum, bool isRedo)
if (ret >= 0)
{
char *segpath = (char *) palloc(strlen(path) + 12);
- BlockNumber segno;
/*
* Note that because we loop until getting ENOENT, we will correctly
* remove all inactive segments as well as active ones.
*/
- for (segno = 1;; segno++)
+ for (;; segno++)
{
- sprintf(segpath, "%s.%u", path, segno);
+ if (segno == 0)
+ strcpy(segpath, path);
+ else
+ sprintf(segpath, "%s.%u", path, segno);
if (!RelFileLocatorBackendIsTemp(rlocator))
{