Skip to content

Commit 46d9bfb

Browse files
committed
Fix race between DROP TABLESPACE and checkpointing.
Commands like ALTER TABLE SET TABLESPACE may leave files for the next checkpoint to clean up. If such files are not removed by the time DROP TABLESPACE is called, we request a checkpoint so that they are deleted. However, there is presently a window before checkpoint start where new unlink requests won't be scheduled until the following checkpoint. This means that the checkpoint forced by DROP TABLESPACE might not remove the files we expect it to remove, and the following ERROR will be emitted: ERROR: tablespace "mytblspc" is not empty To fix, add a call to AbsorbSyncRequests() just before advancing the unlink cycle counter. This ensures that any unlink requests forwarded prior to checkpoint start (i.e., when ckpt_started is incremented) will be processed by the current checkpoint. Since AbsorbSyncRequests() performs memory allocations, it cannot be called within a critical section, so we also need to move SyncPreCheckpoint() to before CreateCheckPoint()'s critical section. This is an old bug, so back-patch to all supported versions. Author: Nathan Bossart <nathandbossart@gmail.com> Reported-by: Nathan Bossart <nathandbossart@gmail.com> Reviewed-by: Thomas Munro <thomas.munro@gmail.com> Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/20220215235845.GA2665318%40nathanxps13
1 parent 4477dcb commit 46d9bfb

File tree

2 files changed

+21
-8
lines changed

2 files changed

+21
-8
lines changed

src/backend/access/transam/xlog.c

+8-7
Original file line numberDiff line numberDiff line change
@@ -6297,6 +6297,14 @@ CreateCheckPoint(int flags)
62976297
MemSet(&CheckpointStats, 0, sizeof(CheckpointStats));
62986298
CheckpointStats.ckpt_start_t = GetCurrentTimestamp();
62996299

6300+
/*
6301+
* Let smgr prepare for checkpoint; this has to happen outside the
6302+
* critical section and before we determine the REDO pointer. Note that
6303+
* smgr must not do anything that'd have to be undone if we decide no
6304+
* checkpoint is needed.
6305+
*/
6306+
SyncPreCheckpoint();
6307+
63006308
/*
63016309
* Use a critical section to force system panic if we have trouble.
63026310
*/
@@ -6310,13 +6318,6 @@ CreateCheckPoint(int flags)
63106318
LWLockRelease(ControlFileLock);
63116319
}
63126320

6313-
/*
6314-
* Let smgr prepare for checkpoint; this has to happen before we determine
6315-
* the REDO pointer. Note that smgr must not do anything that'd have to
6316-
* be undone if we decide no checkpoint is needed.
6317-
*/
6318-
SyncPreCheckpoint();
6319-
63206321
/* Begin filling in the checkpoint WAL record */
63216322
MemSet(&checkPoint, 0, sizeof(checkPoint));
63226323
checkPoint.time = (pg_time_t) time(NULL);

src/backend/storage/sync/sync.c

+13-1
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,26 @@ InitSync(void)
174174
* counter is incremented here.
175175
*
176176
* This must be called *before* the checkpoint REDO point is determined.
177-
* That ensures that we won't delete files too soon.
177+
* That ensures that we won't delete files too soon. Since this calls
178+
* AbsorbSyncRequests(), which performs memory allocations, it cannot be
179+
* called within a critical section.
178180
*
179181
* Note that we can't do anything here that depends on the assumption
180182
* that the checkpoint will be completed.
181183
*/
182184
void
183185
SyncPreCheckpoint(void)
184186
{
187+
/*
188+
* Operations such as DROP TABLESPACE assume that the next checkpoint will
189+
* process all recently forwarded unlink requests, but if they aren't
190+
* absorbed prior to advancing the cycle counter, they won't be processed
191+
* until a future checkpoint. The following absorb ensures that any
192+
* unlink requests forwarded before the checkpoint began will be processed
193+
* in the current checkpoint.
194+
*/
195+
AbsorbSyncRequests();
196+
185197
/*
186198
* Any unlink requests arriving after this point will be assigned the next
187199
* cycle counter, and won't be unlinked until next checkpoint.

0 commit comments

Comments
 (0)