Skip to content

Conversation

@leventov
Copy link

The pg_tde helper binaries decrypt/reencrypt WAL via a temporary file under TMPFS_DIRECTORY (/dev/shm). On very low‑memory systems this tmpfs can fill, and previous behavior left temporary files/directories behind on failures or abrupt termination, compounding ENOSPC and retries.

Changes:

  • Always remove the temporary file and directory on normal exit and on
    SIGINT/SIGTERM (atexit() + signal handlers).
  • Check the tmpfs dir capacity before creating the temp file. The temp file size is taken to be:
    • In archive (pg_tde_restore_encrypt.c): size = encrypted source file size + 4MB slack.
    • In restore (pg_tde_archive_decrypt.c): read xlog_seg_size from pg_control (derived from DEST-PATH
      data dir); fallback to 16MB if unavailable + 4MB slack.
    • If the check fails due to insufficient remaining /dev/shm capacity, exit nonzero with a clear error so Postgres will retry later rather than failing mid‑write.

FWIW, the initial condition that has led this failures was a programming mistake on my part rather than pg_tde's defect, but even then, I think it's better to harden the achirve/restore binaries so that they don't exacerbate the problem by cluttering tmpfs.

I've not tested this patch in a realistic environment yet (I indent to do that, but maybe only the next week or so), yet I would like to publish the patch already for review and feedback.

I'm not an expert in C, Postgres, or pgBackRest; the patch is authored by AI coding agent; but I've reviewed it and it makes sense to me.

@it-percona-cla
Copy link

it-percona-cla commented Sep 17, 2025

CLA assistant check
All committers have signed the CLA.

@jeltz
Copy link
Collaborator

jeltz commented Sep 17, 2025

Thanks for the PR. This is for sure a real bug and we have reported it in our issue tracking system as PG-1932. As a C developer I am not really a fan of what the AI has coded so we will likely write our own patch for it which I hope you do not mind. Again thanks a lot for the bug report and the PR!

@leventov
Copy link
Author

@jeltz thanks for looking into this. No, I don't mind at all. Would be curious to learn the proper fix!

@jeltz
Copy link
Collaborator

jeltz commented Oct 15, 2025

Closing this PR since development is moving to https://github.com/percona/pg_tde. Also I do remember this PR, we have just been very busy with work on PostgreSQL 18 support which is what caused us to split the repos. :)

@jeltz jeltz closed this Oct 15, 2025
jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak tmeporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.
jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak tmeporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAp test framework
testing this seems a pain so no tests are included.
jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak temporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAP test framework
testing this seems a pain so no tests are included.
jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak temporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAP test framework
testing this seems a pain so no tests are included.
jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak temporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAP test framework
testing this seems a pain so no tests are included.
@jeltz
Copy link
Collaborator

jeltz commented Nov 13, 2025

@leventov Sorry for the silence but we have been very busy with the PostgreSQL 18 release which necessitated splitting the repository into two (this one which now only contains our custom hooks and https://github.com/percona/pg_tde which contains the actual extension).

But now there is a PR, percona/pg_tde#467, for fixing this. It will sadly probably not make it to the first pg_tde release with PG 18 support (scheduled to be called 2.1) since code freeze for that has already happened but it will be released in 2.2, whenever that happens.

@leventov
Copy link
Author

@jeltz thank you very much!

jeltz added a commit to jeltz/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak temporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAP test framework
testing this seems a pain so no tests are included.
jeltz added a commit to percona/pg_tde that referenced this pull request Nov 13, 2025
As reported by Roman Leventov in
percona/postgres#582 we had an issue where we
easily could leak temporary files and directories when on failure,
especially when the wrapped restore or archive command fails.

The solution in this commit is to move the cleanup of temporary files
and directories to and atexit() callback plus add a signal handler for
SIGINT and SIGTERM. The signal handler makes sure to kill itself after
running cleanup so the parent process gets the right error.

We have a tiny race condition between creating the temporary directory
and registering the signal handler but that does not seem worth fixing
since it would just leak a directory, not the WAL file, the race
conditions being tiny.

With the current hardcoded path of /dev/shm and the TAP test framework
testing this seems a pain so no tests are included.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants