Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f54d062

Browse files
committed
Fix ALTER TABLE ... SET TABLESPACE for unlogged relations.
Changing the tablespace of an unlogged relation did not WAL log the creation and content of the init fork. Thus, after a standby is promoted, unlogged relation cannot be accessed anymore, with errors like: ERROR: 58P01: could not open file "pg_tblspc/...": No such file or directory Additionally the init fork was not synced to disk, independent of the configured wal_level, a relatively small durability risk. Investigation of that problem also brought to light that, even for permanent relations, the creation of !main forks was not WAL logged, i.e. no XLOG_SMGR_CREATE record were emitted. That mostly turns out not to be a problem, because these files were created when the actual relation data is copied; nonexistent files are not treated as an error condition during replay. But that doesn't work for empty files, and generally feels a bit haphazard. Luckily, outside init and main forks, empty forks don't occur often or are not a problem. Add the required WAL logging and syncing to disk. Reported-By: Michael Paquier Author: Michael Paquier and Andres Freund Discussion: 20151210163230.GA11331@alap3.anarazel.de Backpatch: 9.1, where unlogged relations were introduced
1 parent 085423e commit f54d062

File tree

1 file changed

+22
-2
lines changed

1 file changed

+22
-2
lines changed

src/backend/commands/tablecmds.c

+22-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "catalog/pg_type.h"
4343
#include "catalog/pg_type_fn.h"
4444
#include "catalog/storage.h"
45+
#include "catalog/storage_xlog.h"
4546
#include "catalog/toasting.h"
4647
#include "commands/cluster.h"
4748
#include "commands/comment.h"
@@ -9659,6 +9660,15 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
96599660
if (smgrexists(rel->rd_smgr, forkNum))
96609661
{
96619662
smgrcreate(dstrel, forkNum, false);
9663+
9664+
/*
9665+
* WAL log creation if the relation is persistent, or this is the
9666+
* init fork of an unlogged relation.
9667+
*/
9668+
if (rel->rd_rel->relpersistence == RELPERSISTENCE_PERMANENT ||
9669+
(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
9670+
forkNum == INIT_FORKNUM))
9671+
log_smgrcreate(&newrnode, forkNum);
96629672
copy_relation_data(rel->rd_smgr, dstrel, forkNum,
96639673
rel->rd_rel->relpersistence);
96649674
}
@@ -9878,6 +9888,7 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
98789888
char *buf;
98799889
Page page;
98809890
bool use_wal;
9891+
bool copying_initfork;
98819892
BlockNumber nblocks;
98829893
BlockNumber blkno;
98839894

@@ -9890,11 +9901,20 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
98909901
buf = (char *) palloc(BLCKSZ);
98919902
page = (Page) buf;
98929903

9904+
/*
9905+
* The init fork for an unlogged relation in many respects has to be
9906+
* treated the same as normal relation, changes need to be WAL logged and
9907+
* it needs to be synced to disk.
9908+
*/
9909+
copying_initfork = relpersistence == RELPERSISTENCE_UNLOGGED &&
9910+
forkNum == INIT_FORKNUM;
9911+
98939912
/*
98949913
* We need to log the copied data in WAL iff WAL archiving/streaming is
98959914
* enabled AND it's a permanent relation.
98969915
*/
9897-
use_wal = XLogIsNeeded() && relpersistence == RELPERSISTENCE_PERMANENT;
9916+
use_wal = XLogIsNeeded() &&
9917+
(relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork);
98989918

98999919
nblocks = smgrnblocks(src, forkNum);
99009920

@@ -9949,7 +9969,7 @@ copy_relation_data(SMgrRelation src, SMgrRelation dst,
99499969
* wouldn't replay our earlier WAL entries. If we do not fsync those pages
99509970
* here, they might still not be on disk when the crash occurs.
99519971
*/
9952-
if (relpersistence == RELPERSISTENCE_PERMANENT)
9972+
if (relpersistence == RELPERSISTENCE_PERMANENT || copying_initfork)
99539973
smgrimmedsync(dst, forkNum);
99549974
}
99559975

0 commit comments

Comments
 (0)