aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_basebackup/pg_basebackup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/pg_basebackup/pg_basebackup.c')
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c134
1 files changed, 119 insertions, 15 deletions
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 9d7a1e38add..919805f5cfa 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -12,10 +12,6 @@
*/
#include "postgres_fe.h"
-#include "libpq-fe.h"
-#include "pqexpbuffer.h"
-#include "pgtar.h"
-#include "pgtime.h"
#include <unistd.h>
#include <dirent.h>
@@ -30,8 +26,12 @@
#endif
#include "getopt_long.h"
-
+#include "libpq-fe.h"
+#include "pqexpbuffer.h"
+#include "pgtar.h"
+#include "pgtime.h"
#include "receivelog.h"
+#include "replication/basebackup.h"
#include "streamutil.h"
@@ -65,6 +65,8 @@ static bool fastcheckpoint = false;
static bool writerecoveryconf = false;
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
static pg_time_t last_progress_report = 0;
+static int32 maxrate = 0; /* no limit by default */
+
/* Progress counters */
static uint64 totalsize;
@@ -226,6 +228,7 @@ usage(void)
printf(_("\nOptions controlling the output:\n"));
printf(_(" -D, --pgdata=DIRECTORY receive base backup into directory\n"));
printf(_(" -F, --format=p|t output format (plain (default), tar)\n"));
+ printf(_(" -r, --max-rate=RATE maximum transfer rate to transfer data directory\n"));
printf(_(" -R, --write-recovery-conf\n"
" write recovery.conf after backup\n"));
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
@@ -606,6 +609,97 @@ progress_report(int tablespacenum, const char *filename, bool force)
fprintf(stderr, "\r");
}
+static int32
+parse_max_rate(char *src)
+{
+ double result;
+ char *after_num;
+ char *suffix = NULL;
+
+ errno = 0;
+ result = strtod(src, &after_num);
+ if (src == after_num)
+ {
+ fprintf(stderr,
+ _("%s: transfer rate \"%s\" is not a valid value\n"),
+ progname, src);
+ exit(1);
+ }
+ if (errno != 0)
+ {
+ fprintf(stderr,
+ _("%s: invalid transfer rate \"%s\": %s\n"),
+ progname, src, strerror(errno));
+ exit(1);
+ }
+
+ if (result <= 0)
+ {
+ /*
+ * Reject obviously wrong values here.
+ */
+ fprintf(stderr, _("%s: transfer rate must be greater than zero\n"),
+ progname);
+ exit(1);
+ }
+
+ /*
+ * Evaluate suffix, after skipping over possible whitespace.
+ * Lack of suffix means kilobytes.
+ */
+ while (*after_num != '\0' && isspace((unsigned char) *after_num))
+ after_num++;
+
+ if (*after_num != '\0')
+ {
+ suffix = after_num;
+ if (*after_num == 'k')
+ {
+ /* kilobyte is the expected unit. */
+ after_num++;
+ }
+ else if (*after_num == 'M')
+ {
+ after_num++;
+ result *= 1024.0;
+ }
+ }
+
+ /* The rest can only consist of white space. */
+ while (*after_num != '\0' && isspace((unsigned char) *after_num))
+ after_num++;
+
+ if (*after_num != '\0')
+ {
+ fprintf(stderr,
+ _("%s: invalid --max-rate units: \"%s\"\n"),
+ progname, suffix);
+ exit(1);
+ }
+
+ /* Valid integer? */
+ if ((uint64) result != (uint64) ((uint32) result))
+ {
+ fprintf(stderr,
+ _("%s: transfer rate \"%s\" exceeds integer range\n"),
+ progname, src);
+ exit(1);
+ }
+
+ /*
+ * The range is checked on the server side too, but avoid the server
+ * connection if a nonsensical value was passed.
+ */
+ if (result < MAX_RATE_LOWER || result > MAX_RATE_UPPER)
+ {
+ fprintf(stderr,
+ _("%s: transfer rate \"%s\" is out of range\n"),
+ progname, src);
+ exit(1);
+ }
+
+ return (int32) result;
+}
/*
* Write a piece of tar data
@@ -1485,8 +1579,9 @@ BaseBackup(void)
char *sysidentifier;
uint32 latesttli;
uint32 starttli;
- char current_path[MAXPGPATH];
+ char *basebkp;
char escaped_label[MAXPGPATH];
+ char *maxrate_clause = NULL;
int i;
char xlogstart[64];
char xlogend[64];
@@ -1559,15 +1654,20 @@ BaseBackup(void)
* Start the actual backup
*/
PQescapeStringConn(conn, escaped_label, label, sizeof(escaped_label), &i);
- snprintf(current_path, sizeof(current_path),
- "BASE_BACKUP LABEL '%s' %s %s %s %s",
- escaped_label,
- showprogress ? "PROGRESS" : "",
- includewal && !streamwal ? "WAL" : "",
- fastcheckpoint ? "FAST" : "",
- includewal ? "NOWAIT" : "");
- if (PQsendQuery(conn, current_path) == 0)
+ if (maxrate > 0)
+ maxrate_clause = psprintf("MAX_RATE %u", maxrate);
+
+ basebkp =
+ psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s",
+ escaped_label,
+ showprogress ? "PROGRESS" : "",
+ includewal && !streamwal ? "WAL" : "",
+ fastcheckpoint ? "FAST" : "",
+ includewal ? "NOWAIT" : "",
+ maxrate_clause ? maxrate_clause : "");
+
+ if (PQsendQuery(conn, basebkp) == 0)
{
fprintf(stderr, _("%s: could not send replication command \"%s\": %s"),
progname, "BASE_BACKUP", PQerrorMessage(conn));
@@ -1847,6 +1947,7 @@ main(int argc, char **argv)
{"pgdata", required_argument, NULL, 'D'},
{"format", required_argument, NULL, 'F'},
{"checkpoint", required_argument, NULL, 'c'},
+ {"max-rate", required_argument, NULL, 'r'},
{"write-recovery-conf", no_argument, NULL, 'R'},
{"tablespace-mapping", required_argument, NULL, 'T'},
{"xlog", no_argument, NULL, 'x'},
@@ -1888,7 +1989,7 @@ main(int argc, char **argv)
}
}
- while ((c = getopt_long(argc, argv, "D:F:RT:xX:l:zZ:d:c:h:p:U:s:wWvP",
+ while ((c = getopt_long(argc, argv, "D:F:r:RT:xX:l:zZ:d:c:h:p:U:s:wWvP",
long_options, &option_index)) != -1)
{
switch (c)
@@ -1909,6 +2010,9 @@ main(int argc, char **argv)
exit(1);
}
break;
+ case 'r':
+ maxrate = parse_max_rate(optarg);
+ break;
case 'R':
writerecoveryconf = true;
break;