Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d0bbe21

Browse filesBrowse files
committed
Free disk space for dropped relations on commit.
When committing a transaction that dropped a relation, we previously truncated only the first segment file to free up disk space (the one that won't be unlinked until the next checkpoint). Truncate higher numbered segments too, even though we unlink them on commit. This frees the disk space immediately, even if other backends have open file descriptors and might take a long time to get around to handling shared invalidation events and closing them. Also extend the same behavior to the first segment, in recovery. Back-patch to all supported releases. Bug: #16663 Reported-by: Denis Patron <denis.patron@previnet.it> Reviewed-by: Pavel Borisov <pashkin.elfe@gmail.com> Reviewed-by: Neil Chen <carpenter.nail.cz@gmail.com> Reviewed-by: David Zhang <david.zhang@highgo.ca> Discussion: https://postgr.es/m/16663-fe97ccf9932fc800%40postgresql.org
1 parent b3d33bf commit d0bbe21
Copy full SHA for d0bbe21

File tree

Expand file treeCollapse file tree

1 file changed

+65
-24
lines changed
Filter options
  • src/backend/storage/smgr
Expand file treeCollapse file tree

1 file changed

+65
-24
lines changed

‎src/backend/storage/smgr/md.c

Copy file name to clipboardExpand all lines: src/backend/storage/smgr/md.c
+65-24Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,41 @@ mdunlink(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
408408
mdunlinkfork(rnode, forkNum, isRedo);
409409
}
410410

411+
/*
412+
* Truncate a file to release disk space.
413+
*/
414+
static int
415+
do_truncate(char *path)
416+
{
417+
int save_errno;
418+
int ret;
419+
int fd;
420+
421+
/* truncate(2) would be easier here, but Windows hasn't got it */
422+
fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
423+
if (fd >= 0)
424+
{
425+
ret = ftruncate(fd, 0);
426+
save_errno = errno;
427+
CloseTransientFile(fd);
428+
errno = save_errno;
429+
}
430+
else
431+
ret = -1;
432+
433+
/* Log a warning here to avoid repetition in callers. */
434+
if (ret < 0 && errno != ENOENT)
435+
{
436+
save_errno = errno;
437+
ereport(WARNING,
438+
(errcode_for_file_access(),
439+
errmsg("could not truncate file \"%s\": %m", path)));
440+
errno = save_errno;
441+
}
442+
443+
return ret;
444+
}
445+
411446
static void
412447
mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
413448
{
@@ -421,33 +456,28 @@ mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
421456
*/
422457
if (isRedo || forkNum != MAIN_FORKNUM || RelFileNodeBackendIsTemp(rnode))
423458
{
424-
ret = unlink(path);
425-
if (ret < 0 && errno != ENOENT)
426-
ereport(WARNING,
427-
(errcode_for_file_access(),
428-
errmsg("could not remove file \"%s\": %m", path)));
429-
}
430-
else
431-
{
432-
/* truncate(2) would be easier here, but Windows hasn't got it */
433-
int fd;
434-
435-
fd = OpenTransientFile(path, O_RDWR | PG_BINARY, 0);
436-
if (fd >= 0)
459+
if (!RelFileNodeBackendIsTemp(rnode))
437460
{
438-
int save_errno;
439-
440-
ret = ftruncate(fd, 0);
441-
save_errno = errno;
442-
CloseTransientFile(fd);
443-
errno = save_errno;
461+
/* Prevent other backends' fds from holding on to the disk space */
462+
ret = do_truncate(path);
444463
}
445464
else
446-
ret = -1;
447-
if (ret < 0 && errno != ENOENT)
448-
ereport(WARNING,
449-
(errcode_for_file_access(),
450-
errmsg("could not truncate file \"%s\": %m", path)));
465+
ret = 0;
466+
467+
/* Next unlink the file, unless it was already found to be missing */
468+
if (ret == 0 || errno != ENOENT)
469+
{
470+
ret = unlink(path);
471+
if (ret < 0 && errno != ENOENT)
472+
ereport(WARNING,
473+
(errcode_for_file_access(),
474+
errmsg("could not remove file \"%s\": %m", path)));
475+
}
476+
}
477+
else
478+
{
479+
/* Prevent other backends' fds from holding on to the disk space */
480+
ret = do_truncate(path);
451481

452482
/* Register request to unlink first segment later */
453483
register_unlink(rnode);
@@ -468,6 +498,17 @@ mdunlinkfork(RelFileNodeBackend rnode, ForkNumber forkNum, bool isRedo)
468498
for (segno = 1;; segno++)
469499
{
470500
sprintf(segpath, "%s.%u", path, segno);
501+
502+
if (!RelFileNodeBackendIsTemp(rnode))
503+
{
504+
/*
505+
* Prevent other backends' fds from holding on to the disk
506+
* space.
507+
*/
508+
if (do_truncate(segpath) < 0 && errno == ENOENT)
509+
break;
510+
}
511+
471512
if (unlink(segpath) < 0)
472513
{
473514
/* ENOENT is expected after the last segment... */

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.