diff -Nrpcd a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml *** a/doc/src/sgml/backup.sgml 2014-06-10 13:17:05.000000000 +0900 --- b/doc/src/sgml/backup.sgml 2014-06-17 23:04:59.289759300 +0900 *************** tar -cf backup.tar /usr/local/pgsql/data *** 602,609 **** character in the command. The simplest useful command is something like: ! archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' # Unix ! archive_command = 'copy "%p" "C:\\server\\archivedir\\%f"' # Windows which will copy archivable WAL segments to the directory /mnt/server/archivedir. (This is an example, not a --- 602,609 ---- character in the command. The simplest useful command is something like: ! archive_command = 'test ! -f /mnt/server/archivedir/%f && pg_copy %p /mnt/server/archivedir/%f.tmp && mv /mnt/server/archivedir/%f.tmp /mnt/server/archivedir/%f' # Unix ! archive_command = 'pg_copy "%p" "C:\\server\\archivedir\\%f.tmp" && move "C:\\server\\archivedir\\%f.tmp" "C:\\server\\archivedir\\%f"' # Windows which will copy archivable WAL segments to the directory /mnt/server/archivedir. (This is an example, not a *************** archive_command = 'copy "%p" "C:\\server *** 611,622 **** %p and %f parameters have been replaced, the actual command executed might look like this: ! test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_xlog/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065 A similar command will be generated for each new file to be archived. The archive command will be executed under the ownership of the same user that the PostgreSQL server is running as. Since the series of WAL files being archived contains effectively everything --- 611,634 ---- %p and %f parameters have been replaced, the actual command executed might look like this: ! test ! -f /mnt/server/archivedir/00000001000000A900000065 && pg_copy pg_xlog/00000001000000A900000065 /mnt/server/archivedir/00000001000000A900000065.tmp && mv /mnt/server/archivedir/00000001000000A900000065.tmp /mnt/server/archivedir/00000001000000A900000065 A similar command will be generated for each new file to be archived. + It is recommended that you use pg_copy instead of + standard operating system commands such as cp or + copy. Those commands do not synchronize the data + to disk, so the copied WAL files might be lost in case of power loss, + operating system failure, and hardware failure even when those commands + complete successfully. pg_copy forces writes from the + operating system buffer cache to disk. Make sure to include the directory + for executable files in your shell's search path when you start the database + server, so that the server can find pg_copy. + + + The archive command will be executed under the ownership of the same user that the PostgreSQL server is running as. Since the series of WAL files being archived contains effectively everything diff -Nrpcd a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml *** a/doc/src/sgml/ref/allfiles.sgml 2014-06-10 13:17:05.000000000 +0900 --- b/doc/src/sgml/ref/allfiles.sgml 2014-06-17 23:04:59.425759300 +0900 *************** Complete list of usable sgml source file *** 178,183 **** --- 178,184 ---- + diff -Nrpcd a/doc/src/sgml/ref/pg_copy.sgml b/doc/src/sgml/ref/pg_copy.sgml *** a/doc/src/sgml/ref/pg_copy.sgml 1970-01-01 09:00:00.000000000 +0900 --- b/doc/src/sgml/ref/pg_copy.sgml 2014-06-17 23:04:59.455759300 +0900 *************** *** 0 **** --- 1,110 ---- + + + + + pg_copy + 1 + Application + + + + pg_copy + copy regular files synchronously + + + + pg_copy + + + + + pg_copy + option + source + dest + + + + + Description + + + pg_copy copies a regular file from source to dest, forcing data to disk. This simple utility is intended to be used for archiving write-ahead log (WAL) files instead of standard operating system utilities such as cp or copy. + + + + + + + Options + + + pg_copy accepts the following command-line arguments: + + + + + + + + Specifies the size in kilobytes of the buffer for copying data. + The default is 1024. + + + + + + + + + + Use direct I/O for writing the destination file. Direct I/O + contributes to speedup by bypassing the file system cache. + If direct I/O is not available on the platform, this option has no effect. + + + + + + + + + + Print the pg_copy version and exit. + + + + + + + + + + Show help about pg_copy command line + arguments, and exit. + + + + + + + + + + + + Notes + + + On UNIX/Linux systems, the permissions of the + destination file are 0600, meaning that + only the user who executes this command can read + and write the file. + + + + + diff -Nrpcd a/doc/src/sgml/reference.sgml b/doc/src/sgml/reference.sgml *** a/doc/src/sgml/reference.sgml 2014-06-10 13:17:05.000000000 +0900 --- b/doc/src/sgml/reference.sgml 2014-06-17 23:04:59.479759300 +0900 *************** *** 254,259 **** --- 254,260 ---- &initdb; &pgControldata; + &pgcopy; &pgCtl; &pgResetxlog; &postgres; diff -Nrpcd a/src/bin/Makefile b/src/bin/Makefile *** a/src/bin/Makefile 2014-06-10 13:17:05.000000000 +0900 --- b/src/bin/Makefile 2014-06-17 23:04:59.552759300 +0900 *************** top_builddir = ../.. *** 14,20 **** include $(top_builddir)/src/Makefile.global SUBDIRS = initdb pg_ctl pg_dump \ ! psql scripts pg_config pg_controldata pg_resetxlog pg_basebackup ifeq ($(PORTNAME), win32) SUBDIRS += pgevent --- 14,20 ---- include $(top_builddir)/src/Makefile.global SUBDIRS = initdb pg_ctl pg_dump \ ! psql scripts pg_config pg_controldata pg_resetxlog pg_basebackup pg_copy ifeq ($(PORTNAME), win32) SUBDIRS += pgevent diff -Nrpcd a/src/bin/pg_copy/.gitignore b/src/bin/pg_copy/.gitignore *** a/src/bin/pg_copy/.gitignore 1970-01-01 09:00:00.000000000 +0900 --- b/src/bin/pg_copy/.gitignore 2014-06-17 23:04:59.577759300 +0900 *************** *** 0 **** --- 1,2 ---- + /pg_copy + /tmp_check/ diff -Nrpcd a/src/bin/pg_copy/Makefile b/src/bin/pg_copy/Makefile *** a/src/bin/pg_copy/Makefile 1970-01-01 09:00:00.000000000 +0900 --- b/src/bin/pg_copy/Makefile 2014-06-17 23:04:59.618759300 +0900 *************** *** 0 **** --- 1,42 ---- + #------------------------------------------------------------------------- + # + # Makefile for src/bin/pg_copy + # + # Copyright (c) 2014, PostgreSQL Global Development Group + # + # src/bin/pg_copy/Makefile + # + #------------------------------------------------------------------------- + + PGFILEDESC = "pg_copy - copy a regular file synchronously" + PGAPPICON=win32 + + subdir = src/bin/pg_copy + top_builddir = ../../.. + include $(top_builddir)/src/Makefile.global + + OBJS= pg_copy.o $(WIN32RES) + + all: pg_copy + + pg_copy: $(OBJS) | submake-libpgport + $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X) + + install: all installdirs + $(INSTALL_SCRIPT) pg_copy$(X) '$(DESTDIR)$(bindir)/pg_copy$(X)' + + installdirs: + $(MKDIR_P) '$(DESTDIR)$(bindir)' + + uninstall: + rm -f '$(DESTDIR)$(bindir)/pg_copy$(X)' + + clean distclean maintainer-clean: + rm -f pg_copy$(X) $(OBJS) + rm -rf tmp_check + + check: all + $(prove_check) + + installcheck: + $(prove_installcheck) diff -Nrpcd a/src/bin/pg_copy/nls.mk b/src/bin/pg_copy/nls.mk *** a/src/bin/pg_copy/nls.mk 1970-01-01 09:00:00.000000000 +0900 --- b/src/bin/pg_copy/nls.mk 2014-06-17 23:04:59.630759300 +0900 *************** *** 0 **** --- 1,4 ---- + # src/bin/pg_copy/nls.mk + CATALOG_NAME = pg_copy + AVAIL_LANGUAGES = cs de es fr it ja ko nb pl pt_BR ro ru sv ta tr zh_CN zh_TW + GETTEXT_FILES = pg_copy.c diff -Nrpcd a/src/bin/pg_copy/pg_copy.c b/src/bin/pg_copy/pg_copy.c *** a/src/bin/pg_copy/pg_copy.c 1970-01-01 09:00:00.000000000 +0900 --- b/src/bin/pg_copy/pg_copy.c 2014-06-17 23:05:40.856759300 +0900 *************** *** 0 **** --- 1,235 ---- + /*------------------------------------------------------------------------- + * + * pg_copy.c + * + * Portions Copyright (c) 2014, PostgreSQL Global Development Group + * + * src/bin/pg_copy/pg_copy.c + */ + + #include "postgres_fe.h" + + #include + #include + #include + #include + #include + #include + #include + #include + + #include "getopt_long.h" + + #define BUFFER_ALIGNMENT 8192 + + static const char *progname; + + static void usage(void); + static void copy_file(char *fromfile, char *tofile, int buffer_size, bool directio); + + + int + main(int argc, char **argv) + { + static struct option long_options[] = { + {"buffersize", required_argument, NULL, 'b'}, + {"directio", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, '?'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} + }; + int c, + optindex; + bool directio = false; + int buffer_size = 1024; + char *endptr; + + set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_copy")); + progname = get_progname(argv[0]); + + if (argc > 1) + { + if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0 || + strcmp(argv[1], "-h") == 0) + { + usage(); + exit(0); + } + if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) + { + puts("pg_copy (PostgreSQL) " PG_VERSION); + exit(0); + } + } + + while ((c = getopt_long(argc, argv, "b:d", long_options, &optindex)) != -1) + { + switch (c) + { + case 'b': + buffer_size = (int) strtol(optarg, &endptr, 10); + if (*endptr != '\0' || + buffer_size < BUFFER_ALIGNMENT / 1024 || + buffer_size % (BUFFER_ALIGNMENT / 1024) != 0) + { + fprintf(stderr, _("%s: buffer size is wrong\n"), progname); + exit(1); + } + buffer_size *= 1024; + break; + case 'd': + directio = true; + break; + default: + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(1); + } + } + + if (argc - optind < 2) + { + fprintf(stderr, _("%s: source or destination file is not specified\n"), progname); + exit(1); + } + else if (argc - optind > 2) + { + fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"), + progname, argv[optind + 2]); + fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); + exit(1); + } + + copy_file(argv[optind], argv[optind + 1], buffer_size, directio); + + return 0; + } + + static void + usage(void) + { + printf(_("\n%s copies a regular file synchronously.\n\n"), progname); + printf(_("Usage:\n")); + printf(_(" %s [OPTION...] source_path dest_path\n"), progname); + printf(_("Options:\n")); + printf(_(" -b, --buffersize=BUFFERSIZE\n")); + printf(_(" buffer size (KB) for copying data\n")); + printf(_(" -d, --directio use direct I/O\n")); + printf(_(" -V, --version output version information, then exit\n")); + printf(_(" -?, --help show this help, then exit\n")); + printf(_("Report bugs to .\n")); + } + + static void + copy_file(char *fromfile, char *tofile, int buffer_size, bool directio) + { + char *buffer, *orig_buffer; + int srcfd, + dstfd; + int nbytes, + written_size = 0; + int mode; + + /* + * Allocate a buffer for file I/O, considering the alignment for O_DIRECT. + */ + orig_buffer = malloc(buffer_size + BUFFER_ALIGNMENT); + if (orig_buffer == NULL) + { + fprintf(stderr, _("out of memory\n")); + exit(1); + } + buffer = (char *) TYPEALIGN(BUFFER_ALIGNMENT, orig_buffer); + + mode = O_WRONLY | O_CREAT | O_TRUNC | PG_BINARY; + #ifdef O_SYNC + mode |= O_SYNC; + #endif + + /* + * If direct I/O is available on the platform, and + * the file size is a multiple of the buffer alignment size, use it. + */ + #ifdef O_DIRECT + if (directio) + { + struct stat stat_buf; + + if (stat(fromfile, &stat_buf) == 0 && + stat_buf.st_size % BUFFER_ALIGNMENT == 0) + mode |= O_DIRECT; + } + #endif + + srcfd = open(fromfile, O_RDONLY | PG_BINARY, 0); + if (srcfd < 0) + { + fprintf(stderr, _("could not open file \"%s\": %s\n"), + fromfile, strerror(errno)); + exit(1); + } + + dstfd = open(tofile, mode, + S_IRUSR | S_IWUSR); + if (dstfd < 0) + { + fprintf(stderr, _("could not create file \"%s\": %s\n"), + tofile, strerror(errno)); + exit(1); + } + + /* + * Copy the file content. + */ + for (;;) + { + nbytes = read(srcfd, buffer, buffer_size); + if (nbytes < 0) + { + fprintf(stderr, _("could not read file \"%s\": %s\n"), + fromfile, strerror(errno)); + exit(1); + } + if (nbytes == 0) + break; + + errno = 0; + if (write(dstfd, buffer, nbytes) != nbytes) + { + /* if write didn't set errno, assume problem is no disk space */ + if (errno == 0) + errno = ENOSPC; + fprintf(stderr, _("could not write to file \"%s\": %s\n"), + tofile, strerror(errno)); + exit(1); + } + written_size += nbytes; + } + + /* + * Archived files will not be re-read in normal operation, so we advise the + * OS to release any cached pages. + */ + #if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) + (void) posix_fadvise(dstfd, 0, 0, POSIX_FADV_DONTNEED); + #endif + + #ifndef O_SYNC + if (fsync(dstfd)) + { + fprintf(stderr, _("could not fsync file \"%s\": %s\n"), + tofile, strerror(errno)); + exit(1); + } + #endif + + if (close(dstfd)) + { + fprintf(stderr, _("could not close file \"%s\": %s\n"), + tofile, strerror(errno)); + exit(1); + } + + close(srcfd); + + free(orig_buffer); + } diff -Nrpcd a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm *** a/src/tools/msvc/Mkvcbuild.pm 2014-06-10 13:17:05.000000000 +0900 --- b/src/tools/msvc/Mkvcbuild.pm 2014-06-17 23:04:59.709759300 +0900 *************** sub mkvcbuild *** 382,387 **** --- 382,389 ---- my $pgconfig = AddSimpleFrontend('pg_config'); + my $pgcopy = AddSimpleFrontend('pg_copy'); + my $pgcontrol = AddSimpleFrontend('pg_controldata'); my $pgctl = AddSimpleFrontend('pg_ctl', 1);