On Mon, 2008-06-30 at 19:29 -0400, Andrew Dunstan wrote: > > Bruce Momjian wrote: > > Dave Page wrote: > > > >> On Sun, May 18, 2008 at 1:38 PM, Andrew Dunstan <[EMAIL PROTECTED]> wrote: > >> > >>> I don't know how you tested, > >>> > >> Copy a large file across a relatively slow network, and check the size > >> on the destination drive before it finishes. > >> > >> > >>> but could you please repeat the test with > >>> GnuWin32's cp.exe? If it doesn't preallocate the space then I think our > >>> way > >>> forward is reasonably clear: > >>> > >> It does not pre-allocate. > >> > >> > >>> . we recommend its use for Windows archive_command settings > >>> . we provide the delay kluge as switchable behaviour on Windows instead of > >>> having it always on. > >>> > >> Sounds reasonable to me. > >> > > > > Are there any changes we need to make here? > > > > > > Yes. Simon has promised a patch to do the above.
Patch implements * recommendation to use GnuWin32 cp on Windows * provide "holdtime" delay, default 0 (on all platforms) * default stays same on Windows="copy" to ensure people upgrading don't get stung Patch should be backpatched to 8.3, plus to CVS HEAD. We should recommend in next 8.3 release notes that people use "-p" or "-l" rather than just letting it default. Will add permalink to Wiki when patch appears in archives. -- Simon Riggs www.2ndQuadrant.com PostgreSQL Training, Services and Support
Index: contrib/pg_standby/pg_standby.c =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/contrib/pg_standby/pg_standby.c,v retrieving revision 1.12 diff -c -r1.12 pg_standby.c *** contrib/pg_standby/pg_standby.c 17 May 2008 01:28:21 -0000 1.12 --- contrib/pg_standby/pg_standby.c 1 Jul 2008 08:18:50 -0000 *************** *** 44,49 **** --- 44,50 ---- /* Options and defaults */ int sleeptime = 5; /* amount of time to sleep between file checks */ + int holdtime = 0; /* amount of time to wait once file appears full */ int waittime = -1; /* how long we have been waiting, -1 no wait * yet */ int maxwaittime = 0; /* how long are we prepared to wait for? */ *************** *** 67,75 **** char exclusiveCleanupFileName[MAXPGPATH]; /* the file we need to * get from archive */ ! #define RESTORE_COMMAND_COPY 0 ! #define RESTORE_COMMAND_LINK 1 ! int restoreCommandType; #define XLOG_DATA 0 #define XLOG_HISTORY 1 --- 68,83 ---- char exclusiveCleanupFileName[MAXPGPATH]; /* the file we need to * get from archive */ ! #define RESTORE_COMMAND_CP 0 ! #define RESTORE_COMMAND_LN 1 ! #define RESTORE_COMMAND_WIN32_MKLINK 2 ! #define RESTORE_COMMAND_WIN32_COPY 3 ! #ifdef WIN32 ! int restoreCommandType = RESTORE_COMMAND_WIN32_COPY; ! #else ! int restoreCommandType = RESTORE_COMMAND_CP; ! #endif ! #define XLOG_DATA 0 #define XLOG_HISTORY 1 *************** *** 113,142 **** { #ifdef WIN32 snprintf(WALFilePath, MAXPGPATH, "%s\\%s", archiveLocation, nextWALFileName); switch (restoreCommandType) { ! case RESTORE_COMMAND_LINK: SET_RESTORE_COMMAND("mklink", WALFilePath, xlogFilePath); ! case RESTORE_COMMAND_COPY: ! default: SET_RESTORE_COMMAND("copy", WALFilePath, xlogFilePath); break; ! } ! #else ! snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, nextWALFileName); ! switch (restoreCommandType) ! { ! case RESTORE_COMMAND_LINK: ! #if HAVE_WORKING_LINK SET_RESTORE_COMMAND("ln -s -f", WALFilePath, xlogFilePath); break; ! #endif ! case RESTORE_COMMAND_COPY: ! default: SET_RESTORE_COMMAND("cp", WALFilePath, xlogFilePath); break; } - #endif /* * This code assumes that archiveLocation is a directory You may wish to --- 121,148 ---- { #ifdef WIN32 snprintf(WALFilePath, MAXPGPATH, "%s\\%s", archiveLocation, nextWALFileName); + #else + snprintf(WALFilePath, MAXPGPATH, "%s/%s", archiveLocation, nextWALFileName); + #endif switch (restoreCommandType) { ! case RESTORE_COMMAND_WIN32_MKLINK: SET_RESTORE_COMMAND("mklink", WALFilePath, xlogFilePath); ! case RESTORE_COMMAND_WIN32_COPY: SET_RESTORE_COMMAND("copy", WALFilePath, xlogFilePath); break; ! case RESTORE_COMMAND_LN: SET_RESTORE_COMMAND("ln -s -f", WALFilePath, xlogFilePath); break; ! case RESTORE_COMMAND_CP: SET_RESTORE_COMMAND("cp", WALFilePath, xlogFilePath); break; + default: + fprintf(stderr, "pg_standby: unknown restore command\n"); + fflush(stderr); + exit(2); + break; } /* * This code assumes that archiveLocation is a directory You may wish to *************** *** 175,191 **** } else if (stat_buf.st_size == XLOG_SEG_SIZE) { - #ifdef WIN32 - /* ! * Windows reports that the file has the right number of bytes * even though the file is still being copied and cannot be opened ! * by pg_standby yet. So we wait for sleeptime secs before * attempting to restore. If that is not enough, we will rely on * the retry/holdoff mechanism. */ ! pg_usleep(sleeptime * 1000000L); ! #endif nextWALFileType = XLOG_DATA; return true; } --- 181,196 ---- } else if (stat_buf.st_size == XLOG_SEG_SIZE) { /* ! * Some utilities report that the file has the right number of bytes * even though the file is still being copied and cannot be opened ! * by pg_standby yet. So we wait for holdtime secs before * attempting to restore. If that is not enough, we will rely on * the retry/holdoff mechanism. */ ! if (holdtime > 0) ! pg_usleep(holdtime * 1000000L); ! nextWALFileType = XLOG_DATA; return true; } *************** *** 441,448 **** --- 446,455 ---- fprintf(stderr, " -d generate lots of debugging output (testing only)\n"); fprintf(stderr, " -k NUMFILESTOKEEP if RESTARTWALFILE not used, removes files prior to limit (0 keeps all)\n"); fprintf(stderr, " -l links into archive (leaves file in archive)\n"); + fprintf(stderr, " -p always uses GNU compatible 'cp' command on all platforms\n"); fprintf(stderr, " -r MAXRETRIES max number of times to retry, with progressive wait (default=3)\n"); fprintf(stderr, " -s SLEEPTIME seconds to wait between file checks (min=1, max=60, default=5)\n"); + fprintf(stderr, " -h HOLDTIME seconds to wait once file appears full (min=0, max=60, default=0)\n"); fprintf(stderr, " -t TRIGGERFILE defines a trigger file to initiate failover (no default)\n"); fprintf(stderr, " -w MAXWAITTIME max seconds to wait for a file (0=no limit)(default=0)\n"); fflush(stderr); *************** *** 463,474 **** (void) signal(SIGINT, sighandler); (void) signal(SIGQUIT, sighandler); ! while ((c = getopt(argc, argv, "cdk:lr:s:t:w:")) != -1) { switch (c) { case 'c': /* Use copy */ ! restoreCommandType = RESTORE_COMMAND_COPY; break; case 'd': /* Debug mode */ debug = true; --- 470,488 ---- (void) signal(SIGINT, sighandler); (void) signal(SIGQUIT, sighandler); ! while ((c = getopt(argc, argv, "cdh:k:lpr:s:t:w:")) != -1) { switch (c) { case 'c': /* Use copy */ ! #ifdef WIN32 ! restoreCommandType = RESTORE_COMMAND_WIN32_COPY; ! #else ! restoreCommandType = RESTORE_COMMAND_CP; ! #endif ! break; ! case 'p': /* Use cp */ ! restoreCommandType = RESTORE_COMMAND_CP; break; case 'd': /* Debug mode */ debug = true; *************** *** 483,489 **** } break; case 'l': /* Use link */ ! restoreCommandType = RESTORE_COMMAND_LINK; break; case 'r': /* Retries */ maxretries = atoi(optarg); --- 497,511 ---- } break; case 'l': /* Use link */ ! #ifdef WIN32 ! restoreCommandType = RESTORE_COMMAND_WIN32_MKLINK; ! #else ! #if HAVE_WORKING_LINK ! restoreCommandType = RESTORE_COMMAND_LN; ! #else ! restoreCommandType = RESTORE_COMMAND_CP; ! #endif ! #endif break; case 'r': /* Retries */ maxretries = atoi(optarg); *************** *** 503,508 **** --- 525,539 ---- exit(2); } break; + case 'h': /* Hold time */ + holdtime = atoi(optarg); + if (holdtime < 0 || holdtime > 60) + { + fprintf(stderr, "usage: pg_standby -h holdtime incorrectly set\n"); + usage(); + exit(2); + } + break; case 't': /* Trigger file */ triggerPath = optarg; if (CheckForExternalTrigger()) Index: doc/src/sgml/standby.sgml =================================================================== RCS file: /home/sriggs/pg/REPOSITORY/pgsql/doc/src/sgml/standby.sgml,v retrieving revision 1.1 diff -c -r1.1 standby.sgml *** doc/src/sgml/standby.sgml 10 Nov 2007 23:30:46 -0000 1.1 --- doc/src/sgml/standby.sgml 1 Jul 2008 08:29:16 -0000 *************** *** 136,141 **** --- 136,149 ---- </entry> </row> <row> + <entry>-p</entry> + <entry> + <para> + always use cp command on any platform + </para> + </entry> + </row> + <row> <entry>-r maxretries</entry> <entry> <para> *************** *** 160,165 **** --- 168,182 ---- </entry> </row> <row> + <entry>-h holdtime</entry> + <entry> + the number of seconds to wait once a file appears full. + This is required with some utilities, such as Win32 Copy, which + sets the filesize before it has completed the copy process. + <literal>Default=0</literal> + </entry> + </row> + <row> <entry>-t triggerfile</entry> <entry> the presence of the triggerfile will cause recovery to end *************** *** 228,234 **** *not* in the restore_command, in 8.2, 8.1, 8.0 on Windows. </para> <programlisting> ! restore_command = 'pg_standby -c -d -s 5 -w 0 -t C:\pgsql.trigger.5442 ..\archive %f %p 2>> standby.log' </programlisting> <para> --- 245,251 ---- *not* in the restore_command, in 8.2, 8.1, 8.0 on Windows. </para> <programlisting> ! restore_command = 'pg_standby -c -d -s 5 -h 5 -w 0 -t C:\pgsql.trigger.5442 ..\archive %f %p 2>> standby.log' </programlisting> <para> *************** *** 238,248 **** --- 255,272 ---- <listitem><para>use a copy command to restore WAL files from archive</para></listitem> <listitem><para>produce logfile output in standby.log</para></listitem> <listitem><para>sleep for 5 seconds between checks for next WAL file is full</para></listitem> + <listitem><para>sleep for 5 second after the file appears full</para></listitem> <listitem><para>never timeout if file not found</para></listitem> <listitem><para>stop waiting when a trigger file called C:\pgsql.trigger.5442 appears</para></listitem> </itemizedlist> </listitem> </itemizedlist> + <para> + On Windows you are advised to use GNUWin32's cp utility. The cp utility + does not set filesize until file copying is complete, so there is no + need to use the -h option to introduce additional delays to ensure + correctness. See <ulink url="http://gnuwin32.sourceforge.net/"></ulink> + </para> </sect2> </sect1>
-- Sent via pgsql-patches mailing list (pgsql-patches@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-patches