Hi,
I’ve been encouraged to submit this code as there has been talk in the past
about a simple pgcopy command to use with the archive_command. Currently there
is really no good solution in most base systems without having to introduce a
dedicated third party Postgres solution. The best base system solution and
most commonly used today is rsync which doesn’t fsync the file after completing
the transfer leaving no good recommendations.
I not sure what would need to be done to introduce this into a given
commitfest. Also, would need to know if the command interface is acceptable
and/or other features should be added. It currently is very simple as it just
reads from standard input and saves data to the indicated file.
Please let me know how to proceed.
Thanks,
Rui
Example of local compressed archive:
archive_command=“xz -c %p | fwrite /mnt/server/archivedir/%f”
Example of remote archive via a shell script:
#!/usr/bin/env bash
.
.
.
# SSH Command and options
SSH_CMD="ssh -o ServerAliveInterval=20 $ARCH_SERVER"
STS=3
OUTPUT=$(cat $XLOGFILE | $SSH_CMD "(mkdir -p $ARCH_DIR && fwrite
$ARCH_DIR/$WALFILE) 2>&1")
echo ${PIPESTATUS[@]} | grep -qE '^[0 ]+$'
if [ $? == 0 ]; then
STS=0
fi
exit $STS
fwrite code:
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#define BUFSIZE 131072
int
main(int argc, char *argv[])
{
int fd, r, w;
char *buf;
char *name;
struct stat fstat;
if (argc != 2) {
fprintf(stderr, "usage: fwrite [file]\n");
exit(1);
}
if ((buf = malloc(BUFSIZE)) == NULL)
err(1, "malloc");
++argv;
if ((name = (char *) malloc(strlen(*argv) + 8)) == NULL)
err(1, "malloc");
strcat(strcpy(name, *argv), ".XXXXXX");
if ((fd = mkstemp(name)) < 0)
err(1, "mkstemp");
while ((r = read(STDIN_FILENO, buf, BUFSIZE)) > 0)
if ((w = write(fd, buf, r)) == -1) {
unlink(name);
err(1, "write");
}
if (r < 0)
err(1, "read");
if (lseek(fd, 0, SEEK_CUR) <= 0) {
unlink(name);
errx(1, "zero byte file!");
}
if (fsync(fd) != 0)
err(1, "fsync");
if (close(fd) != 0)
err(1, "close");
if (access(*argv, F_OK) < 0 && errno == ENOENT) {
if (rename(name, *argv) != 0)
err(1, "rename");
} else {
unlink(name);
errx(1, "file exists already!");
}
free(name);
exit(0);
}