2013-01-24 09:35:48 +03:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
2017-04-13 18:37:29 +02:00
|
|
|
* show.c: show backup information.
|
2013-01-24 09:35:48 +03:00
|
|
|
*
|
2017-03-01 15:50:07 +02:00
|
|
|
* Portions Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION
|
|
|
|
* Portions Copyright (c) 2015-2017, Postgres Professional
|
2013-01-24 09:35:48 +03:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2016-11-16 19:34:21 +02:00
|
|
|
#include "pg_probackup.h"
|
2017-03-22 10:13:06 +02:00
|
|
|
#include <time.h>
|
2013-01-24 09:35:48 +03:00
|
|
|
|
2016-11-16 20:32:26 +02:00
|
|
|
static void show_backup_list(FILE *out, parray *backup_list);
|
2013-01-24 09:35:48 +03:00
|
|
|
static void show_backup_detail(FILE *out, pgBackup *backup);
|
|
|
|
|
|
|
|
/*
|
2017-04-13 18:37:29 +02:00
|
|
|
* If 'requested_backup_id' is INVALID_BACKUP_ID, show brief meta information
|
|
|
|
* about all backups in the backup catalog.
|
|
|
|
* If valid backup id is passed, show detailed meta information
|
|
|
|
* about specified backup.
|
2013-01-24 09:35:48 +03:00
|
|
|
*/
|
2017-04-13 18:37:29 +02:00
|
|
|
|
2013-01-24 09:35:48 +03:00
|
|
|
int
|
2017-04-13 18:37:29 +02:00
|
|
|
do_show(time_t requested_backup_id)
|
2013-01-24 09:35:48 +03:00
|
|
|
{
|
2017-04-13 18:37:29 +02:00
|
|
|
if (requested_backup_id != INVALID_BACKUP_ID)
|
2013-01-24 09:35:48 +03:00
|
|
|
{
|
2017-03-06 10:55:12 +02:00
|
|
|
pgBackup *backup;
|
2013-01-24 09:35:48 +03:00
|
|
|
|
2017-04-13 18:37:29 +02:00
|
|
|
backup = read_backup(requested_backup_id);
|
2013-01-24 09:35:48 +03:00
|
|
|
if (backup == NULL)
|
|
|
|
{
|
2017-04-13 18:37:29 +02:00
|
|
|
elog(INFO, "Requested backup \"%s\" is not found.",
|
|
|
|
base36enc(requested_backup_id));
|
|
|
|
/* This is not error */
|
2013-01-24 09:35:48 +03:00
|
|
|
return 0;
|
|
|
|
}
|
2017-03-06 10:55:12 +02:00
|
|
|
|
2013-01-24 09:35:48 +03:00
|
|
|
show_backup_detail(stdout, backup);
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
pgBackupFree(backup);
|
2017-04-13 18:37:29 +02:00
|
|
|
|
2013-01-24 09:35:48 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
parray *backup_list;
|
|
|
|
|
2017-04-13 18:37:29 +02:00
|
|
|
backup_list = catalog_get_backup_list(INVALID_BACKUP_ID);
|
2016-01-14 09:36:39 +02:00
|
|
|
if (backup_list == NULL)
|
2017-04-13 18:37:29 +02:00
|
|
|
elog(ERROR, "Failed to get backup list.");
|
2013-01-24 09:35:48 +03:00
|
|
|
|
2016-11-16 20:32:26 +02:00
|
|
|
show_backup_list(stdout, backup_list);
|
2013-01-24 09:35:48 +03:00
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
parray_walk(backup_list, pgBackupFree);
|
|
|
|
parray_free(backup_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
pretty_size(int64 size, char *buf, size_t len)
|
|
|
|
{
|
|
|
|
int exp = 0;
|
|
|
|
|
|
|
|
/* minus means the size is invalid */
|
|
|
|
if (size < 0)
|
|
|
|
{
|
|
|
|
strncpy(buf, "----", len);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* determine postfix */
|
|
|
|
while (size > 9999)
|
|
|
|
{
|
|
|
|
++exp;
|
|
|
|
size /= 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (exp)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "B", size);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "kB", size);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "MB", size);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "GB", size);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "TB", size);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
snprintf(buf, len, INT64_FORMAT "PB", size);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
strncpy(buf, "***", len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 18:37:29 +02:00
|
|
|
/* TODO Add comment */
|
2013-01-24 09:35:48 +03:00
|
|
|
static TimeLineID
|
|
|
|
get_parent_tli(TimeLineID child_tli)
|
|
|
|
{
|
|
|
|
TimeLineID result = 0;
|
|
|
|
char path[MAXPGPATH];
|
|
|
|
char fline[MAXPGPATH];
|
|
|
|
FILE *fd;
|
|
|
|
|
2014-01-24 16:36:31 +03:00
|
|
|
/* Search history file in archives */
|
|
|
|
snprintf(path, lengthof(path), "%s/%08X.history", arclog_path,
|
|
|
|
child_tli);
|
2013-01-24 09:35:48 +03:00
|
|
|
fd = fopen(path, "rt");
|
|
|
|
if (fd == NULL)
|
|
|
|
{
|
|
|
|
if (errno != ENOENT)
|
2016-01-19 05:41:30 +02:00
|
|
|
elog(ERROR, "could not open file \"%s\": %s", path,
|
2013-01-24 09:35:48 +03:00
|
|
|
strerror(errno));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the file...
|
|
|
|
*/
|
|
|
|
while (fgets(fline, sizeof(fline), fd) != NULL)
|
|
|
|
{
|
|
|
|
/* skip leading whitespace and check for # comment */
|
|
|
|
char *ptr;
|
|
|
|
char *endptr;
|
|
|
|
|
|
|
|
for (ptr = fline; *ptr; ptr++)
|
|
|
|
{
|
|
|
|
if (!IsSpace(*ptr))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*ptr == '\0' || *ptr == '#')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* expect a numeric timeline ID as first field of line */
|
|
|
|
result = (TimeLineID) strtoul(ptr, &endptr, 0);
|
|
|
|
if (endptr == ptr)
|
2016-01-19 05:41:30 +02:00
|
|
|
elog(ERROR,
|
2016-01-14 09:36:39 +02:00
|
|
|
"syntax error(timeline ID) in history file: %s",
|
2013-01-24 09:35:48 +03:00
|
|
|
fline);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fd);
|
|
|
|
|
|
|
|
/* TLI of the last line is parent TLI */
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2016-11-16 20:32:26 +02:00
|
|
|
show_backup_list(FILE *out, parray *backup_list)
|
2013-01-24 09:35:48 +03:00
|
|
|
{
|
2017-03-06 10:55:12 +02:00
|
|
|
int i;
|
2013-01-24 09:35:48 +03:00
|
|
|
|
|
|
|
/* show header */
|
2017-03-22 10:46:31 +02:00
|
|
|
fputs("==================================================================================================================\n", out);
|
|
|
|
fputs("ID Recovery time Mode Current/Parent TLI Time Data Start LSN Stop LSN Status \n", out);
|
|
|
|
fputs("==================================================================================================================\n", out);
|
2013-01-24 09:35:48 +03:00
|
|
|
|
|
|
|
for (i = 0; i < parray_num(backup_list); i++)
|
|
|
|
{
|
2017-03-06 10:55:12 +02:00
|
|
|
pgBackup *backup = parray_get(backup_list, i);
|
|
|
|
const char *modes[] = {"", "PAGE", "PTRACK", "FULL", "", "PAGE+STREAM", "PTRACK+STREAM", "FULL+STREAM"};
|
|
|
|
TimeLineID parent_tli;
|
|
|
|
char timestamp[20] = "----";
|
|
|
|
char duration[20] = "----";
|
|
|
|
char data_bytes_str[10] = "----";
|
|
|
|
|
2017-02-14 16:45:18 +02:00
|
|
|
if (backup->recovery_time != (time_t) 0)
|
|
|
|
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
|
2013-01-24 09:35:48 +03:00
|
|
|
if (backup->end_time != (time_t) 0)
|
2017-03-22 10:44:18 +02:00
|
|
|
snprintf(duration, lengthof(duration), "%.*lfs", 0,
|
2017-03-22 10:13:06 +02:00
|
|
|
difftime(backup->end_time, backup->start_time));
|
2014-01-09 22:11:27 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate Data field, in the case of full backup this shows the
|
2014-01-30 09:58:55 +03:00
|
|
|
* total amount of data. For an differential backup, this size is only
|
|
|
|
* the difference of data accumulated.
|
2014-01-09 22:11:27 +03:00
|
|
|
*/
|
|
|
|
pretty_size(backup->data_bytes, data_bytes_str,
|
|
|
|
lengthof(data_bytes_str));
|
|
|
|
|
2013-12-12 18:53:27 +03:00
|
|
|
/* Get parent timeline before printing */
|
2013-01-24 09:35:48 +03:00
|
|
|
parent_tli = get_parent_tli(backup->tli);
|
|
|
|
|
2017-03-22 10:46:31 +02:00
|
|
|
fprintf(out, "%-8s %-19s %-13s %2d / %-2d %5s %6s %2X/%08X %2X/%08X %-8s\n",
|
2016-10-31 17:19:11 +02:00
|
|
|
base36enc(backup->start_time),
|
2014-01-09 22:11:27 +03:00
|
|
|
timestamp,
|
2016-11-17 17:16:04 +02:00
|
|
|
modes[backup->backup_mode + (BACKUP_MODE_FULL + 1)*backup->stream],
|
2014-01-09 22:11:27 +03:00
|
|
|
backup->tli,
|
|
|
|
parent_tli,
|
|
|
|
duration,
|
|
|
|
data_bytes_str,
|
2017-03-20 18:08:18 +02:00
|
|
|
(uint32) (backup->start_lsn >> 32),
|
|
|
|
(uint32) backup->start_lsn,
|
|
|
|
(uint32) (backup->stop_lsn >> 32),
|
|
|
|
(uint32) backup->stop_lsn,
|
2014-01-09 22:11:27 +03:00
|
|
|
status2str(backup->status));
|
2013-01-24 09:35:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
show_backup_detail(FILE *out, pgBackup *backup)
|
|
|
|
{
|
|
|
|
pgBackupWriteConfigSection(out, backup);
|
|
|
|
pgBackupWriteResultSection(out, backup);
|
|
|
|
}
|