On 18/03/2025 01:08, Jelte Fennema-Nio wrote:
On Mon Feb 24, 2025 at 12:01 PM CET, Jelte Fennema-Nio wrote:
Right after pressing send I realized I could remove two more useless
lines...

Rebased patchset attached (trivial conflict against pg_noreturn
changes).

v7-0001-Adds-a-helper-for-places-that-shell-out-to-system.patch:

/*
 * A custom wrapper around the system() function that calls the necessary
 * functions pre/post-fork.
 */
int
System(const char *command, uint32 wait_event_info)
{
        int                     rc;

        fflush(NULL);
        pgstat_report_wait_start(wait_event_info);

        if (wait_event_info == WAIT_EVENT_RESTORE_COMMAND)
        {
                /*
                 * Set in_restore_command to tell the signal handler that we 
should
                 * exit right away on SIGTERM. This is done for the duration of 
the
                 * system() call because there isn't a good way to break out 
while it
                 * is executing.  Since we might call proc_exit() in a signal 
handler,
                 * it is best to put any additional logic outside of this 
section
                 * where in_restore_command is set to true.
                 */
                in_restore_command = true;

                /*
                 * Also check if we had already received the signal, so that we 
don't
                 * miss a shutdown request received just before this.
                 */
                if (shutdown_requested)
                        proc_exit(1);
        }

        rc = system(command);

        if (wait_event_info == WAIT_EVENT_RESTORE_COMMAND)
                in_restore_command = false;

        pgstat_report_wait_end();
        return rc;
}

Let's move that 'in_restore_command' business to the caller. It's weird modularity for the function to implicitly behave differently for some callers. And 'wait_event_info' should only affect pgstat reporting, not actual behavior.

I don't feel good about the function name. How about pg_system() or something? postmaster/startup.c also seems like a weird place for it; not sure where it belongs but probably not there. Maybe next to OpenPipeStream() in fd.c, or move both to a new file.

v7-0002-Bump-postmaster-soft-open-file-limit-RLIMIT_NOFIL.patch:

@@ -274,6 +275,7 @@ System(const char *command, uint32 wait_event_info)
 {
        int                     rc;
+ RestoreOriginalOpenFileLimit();
        fflush(NULL);
        pgstat_report_wait_start(wait_event_info);
@@ -303,6 +305,7 @@ System(const char *command, uint32 wait_event_info)
                in_restore_command = false;
pgstat_report_wait_end();
+       RestoreCustomOpenFileLimit();
        return rc;
 }

Looks a bit funny that both functions are called Restore<something>(). Not sure what to suggest instead though. Maybe RaiseOpenFileLimit() and LowerOpenFileLimit().

@@ -2724,6 +2873,19 @@ OpenPipeStream(const char *command, const char *mode)
        ReleaseLruFiles();
TryAgain:
+
+       /*
+        * It would be great if we could call RestoreOriginalOpenFileLimit here,
+        * but since popen() also opens a file in the current process (this side
+        * of the pipe) we cannot do so safely. Because we might already have 
many
+        * more files open than the original limit.
+        *
+        * The only way to address this would be implementing a custom popen()
+        * that calls RestoreOriginalOpenFileLimit only around the actual fork
+        * call, but that seems too much effort to handle the corner case where
+        * this external command uses both select() and tries to open more files
+        * than select() allows for.
+        */
        fflush(NULL);
        pqsignal(SIGPIPE, SIG_DFL);
        errno = 0;

What would it take to re-implement popen() with fork+exec? Genuine question; I have a feeling it might be complicated to do correctly on all platforms, but I don't know.

--
Heikki Linnakangas
Neon (https://neon.tech)



Reply via email to