You've already forked pg_probackup
							
							
				mirror of
				https://github.com/postgrespro/pg_probackup.git
				synced 2025-10-31 00:17:52 +02:00 
			
		
		
		
	PGPRO-533: Allow to show backup list in json format
This commit is contained in:
		
							
								
								
									
										24
									
								
								src/backup.c
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								src/backup.c
									
									
									
									
									
								
							| @@ -633,7 +633,7 @@ do_backup_instance(void) | |||||||
| 						* For backup from master wait for previous segment. | 						* For backup from master wait for previous segment. | ||||||
| 						* For backup from replica wait for current segment. | 						* For backup from replica wait for current segment. | ||||||
| 						*/ | 						*/ | ||||||
| 					   !from_replica, backup_files_list); | 					   !current.from_replica, backup_files_list); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (current.backup_mode == BACKUP_MODE_DIFF_PTRACK) | 	if (current.backup_mode == BACKUP_MODE_DIFF_PTRACK) | ||||||
| @@ -815,11 +815,15 @@ do_backup(time_t start_time) | |||||||
| 	pgut_atexit_push(backup_disconnect, NULL); | 	pgut_atexit_push(backup_disconnect, NULL); | ||||||
|  |  | ||||||
| 	current.primary_conninfo = pgut_get_conninfo_string(backup_conn); | 	current.primary_conninfo = pgut_get_conninfo_string(backup_conn); | ||||||
|  |  | ||||||
|  | 	current.compress_alg = compress_alg; | ||||||
|  | 	current.compress_level = compress_level; | ||||||
|  |  | ||||||
| 	/* Confirm data block size and xlog block size are compatible */ | 	/* Confirm data block size and xlog block size are compatible */ | ||||||
| 	confirm_block_size("block_size", BLCKSZ); | 	confirm_block_size("block_size", BLCKSZ); | ||||||
| 	confirm_block_size("wal_block_size", XLOG_BLCKSZ); | 	confirm_block_size("wal_block_size", XLOG_BLCKSZ); | ||||||
|  |  | ||||||
| 	from_replica = pg_is_in_recovery(); | 	current.from_replica = pg_is_in_recovery(); | ||||||
|  |  | ||||||
| 	/* Confirm that this server version is supported */ | 	/* Confirm that this server version is supported */ | ||||||
| 	check_server_version(); | 	check_server_version(); | ||||||
| @@ -859,7 +863,7 @@ do_backup(time_t start_time) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (from_replica) | 	if (current.from_replica) | ||||||
| 	{ | 	{ | ||||||
| 		/* Check master connection options */ | 		/* Check master connection options */ | ||||||
| 		if (master_host == NULL) | 		if (master_host == NULL) | ||||||
| @@ -956,7 +960,7 @@ check_server_version(void) | |||||||
| 			 "server version is %s, must be %s or higher", | 			 "server version is %s, must be %s or higher", | ||||||
| 			 server_version_str, "9.5"); | 			 server_version_str, "9.5"); | ||||||
|  |  | ||||||
| 	if (from_replica && server_version < 90600) | 	if (current.from_replica && server_version < 90600) | ||||||
| 		elog(ERROR, | 		elog(ERROR, | ||||||
| 			 "server version is %s, must be %s or higher for backup from replica", | 			 "server version is %s, must be %s or higher for backup from replica", | ||||||
| 			 server_version_str, "9.6"); | 			 server_version_str, "9.6"); | ||||||
| @@ -1061,7 +1065,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup) | |||||||
| 	params[0] = label; | 	params[0] = label; | ||||||
|  |  | ||||||
| 	/* For replica we call pg_start_backup() on master */ | 	/* For replica we call pg_start_backup() on master */ | ||||||
| 	conn = (from_replica) ? master_conn : backup_conn; | 	conn = (backup->from_replica) ? master_conn : backup_conn; | ||||||
|  |  | ||||||
| 	/* 2nd argument is 'fast'*/ | 	/* 2nd argument is 'fast'*/ | ||||||
| 	params[1] = smooth ? "false" : "true"; | 	params[1] = smooth ? "false" : "true"; | ||||||
| @@ -1106,7 +1110,7 @@ pg_start_backup(const char *label, bool smooth, pgBackup *backup) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* Wait for start_lsn to be replayed by replica */ | 	/* Wait for start_lsn to be replayed by replica */ | ||||||
| 	if (from_replica) | 	if (backup->from_replica) | ||||||
| 		wait_replica_wal_lsn(backup->start_lsn, true); | 		wait_replica_wal_lsn(backup->start_lsn, true); | ||||||
|  |  | ||||||
| 	/* | 	/* | ||||||
| @@ -1554,8 +1558,6 @@ wait_replica_wal_lsn(XLogRecPtr lsn, bool is_start_backup) | |||||||
| { | { | ||||||
| 	uint32		try_count = 0; | 	uint32		try_count = 0; | ||||||
|  |  | ||||||
| 	Assert(from_replica); |  | ||||||
|  |  | ||||||
| 	while (true) | 	while (true) | ||||||
| 	{ | 	{ | ||||||
| 		PGresult   *res; | 		PGresult   *res; | ||||||
| @@ -1650,7 +1652,7 @@ pg_stop_backup(pgBackup *backup) | |||||||
| 		elog(FATAL, "backup is not in progress"); | 		elog(FATAL, "backup is not in progress"); | ||||||
|  |  | ||||||
| 	/* For replica we call pg_stop_backup() on master */ | 	/* For replica we call pg_stop_backup() on master */ | ||||||
| 	conn = (from_replica) ? master_conn : backup_conn; | 	conn = (current.from_replica) ? master_conn : backup_conn; | ||||||
|  |  | ||||||
| 	/* Remove annoying NOTICE messages generated by backend */ | 	/* Remove annoying NOTICE messages generated by backend */ | ||||||
| 	res = pgut_execute(conn, "SET client_min_messages = warning;", | 	res = pgut_execute(conn, "SET client_min_messages = warning;", | ||||||
| @@ -1663,7 +1665,7 @@ pg_stop_backup(pgBackup *backup) | |||||||
| 		const char *params[1]; | 		const char *params[1]; | ||||||
| 		char		name[1024]; | 		char		name[1024]; | ||||||
|  |  | ||||||
| 		if (!from_replica) | 		if (!current.from_replica) | ||||||
| 			snprintf(name, lengthof(name), "pg_probackup, backup_id %s", | 			snprintf(name, lengthof(name), "pg_probackup, backup_id %s", | ||||||
| 					 base36enc(backup->start_time)); | 					 base36enc(backup->start_time)); | ||||||
| 		else | 		else | ||||||
| @@ -1891,7 +1893,7 @@ pg_stop_backup(pgBackup *backup) | |||||||
| 					stream_xlog_path[MAXPGPATH]; | 					stream_xlog_path[MAXPGPATH]; | ||||||
|  |  | ||||||
| 		/* Wait for stop_lsn to be received by replica */ | 		/* Wait for stop_lsn to be received by replica */ | ||||||
| 		if (from_replica) | 		if (backup->from_replica) | ||||||
| 			wait_replica_wal_lsn(stop_backup_lsn, false); | 			wait_replica_wal_lsn(stop_backup_lsn, false); | ||||||
| 		/* | 		/* | ||||||
| 		 * Wait for stop_lsn to be archived or streamed. | 		 * Wait for stop_lsn to be archived or streamed. | ||||||
|   | |||||||
| @@ -385,10 +385,11 @@ pgBackupWriteControl(FILE *out, pgBackup *backup) | |||||||
|  |  | ||||||
| 	fprintf(out, "#Configuration\n"); | 	fprintf(out, "#Configuration\n"); | ||||||
| 	fprintf(out, "backup-mode = %s\n", pgBackupGetBackupMode(backup)); | 	fprintf(out, "backup-mode = %s\n", pgBackupGetBackupMode(backup)); | ||||||
| 	fprintf(out, "stream = %s\n", backup->stream?"true":"false"); | 	fprintf(out, "stream = %s\n", backup->stream ? "true" : "false"); | ||||||
| 	fprintf(out, "compress-alg = %s\n", deparse_compress_alg(compress_alg)); | 	fprintf(out, "compress-alg = %s\n", | ||||||
| 	fprintf(out, "compress-level = %d\n", compress_level); | 			deparse_compress_alg(backup->compress_alg)); | ||||||
| 	fprintf(out, "from-replica = %s\n", from_replica?"true":"false"); | 	fprintf(out, "compress-level = %d\n", backup->compress_level); | ||||||
|  | 	fprintf(out, "from-replica = %s\n", backup->from_replica ? "true" : "false"); | ||||||
| 	 | 	 | ||||||
| 	fprintf(out, "\n#Compatibility\n"); | 	fprintf(out, "\n#Compatibility\n"); | ||||||
| 	fprintf(out, "block-size = %u\n", backup->block_size); | 	fprintf(out, "block-size = %u\n", backup->block_size); | ||||||
| @@ -429,7 +430,7 @@ pgBackupWriteControl(FILE *out, pgBackup *backup) | |||||||
| 	if (backup->data_bytes != BYTES_INVALID) | 	if (backup->data_bytes != BYTES_INVALID) | ||||||
| 		fprintf(out, "data-bytes = " INT64_FORMAT "\n", backup->data_bytes); | 		fprintf(out, "data-bytes = " INT64_FORMAT "\n", backup->data_bytes); | ||||||
|  |  | ||||||
| 	if (backup->data_bytes != BYTES_INVALID) | 	if (backup->wal_bytes != BYTES_INVALID) | ||||||
| 		fprintf(out, "wal-bytes = " INT64_FORMAT "\n", backup->wal_bytes); | 		fprintf(out, "wal-bytes = " INT64_FORMAT "\n", backup->wal_bytes); | ||||||
|  |  | ||||||
| 	fprintf(out, "status = %s\n", status2str(backup->status)); | 	fprintf(out, "status = %s\n", status2str(backup->status)); | ||||||
| @@ -475,10 +476,8 @@ readBackupControlFile(const char *path) | |||||||
| 	char	   *stop_lsn = NULL; | 	char	   *stop_lsn = NULL; | ||||||
| 	char	   *status = NULL; | 	char	   *status = NULL; | ||||||
| 	char	   *parent_backup = NULL; | 	char	   *parent_backup = NULL; | ||||||
| 	char	   *compress_alg = NULL; |  | ||||||
| 	char	   *server_version = NULL; | 	char	   *server_version = NULL; | ||||||
| 	int		   *compress_level; | 	char	   *compress_alg = NULL; | ||||||
| 	bool	   *from_replica; |  | ||||||
|  |  | ||||||
| 	pgut_option options[] = | 	pgut_option options[] = | ||||||
| 	{ | 	{ | ||||||
| @@ -500,8 +499,8 @@ readBackupControlFile(const char *path) | |||||||
| 		{'s', 0, "status",				&status, SOURCE_FILE_STRICT}, | 		{'s', 0, "status",				&status, SOURCE_FILE_STRICT}, | ||||||
| 		{'s', 0, "parent-backup-id",	&parent_backup, SOURCE_FILE_STRICT}, | 		{'s', 0, "parent-backup-id",	&parent_backup, SOURCE_FILE_STRICT}, | ||||||
| 		{'s', 0, "compress-alg",		&compress_alg, SOURCE_FILE_STRICT}, | 		{'s', 0, "compress-alg",		&compress_alg, SOURCE_FILE_STRICT}, | ||||||
| 		{'u', 0, "compress-level",		&compress_level, SOURCE_FILE_STRICT}, | 		{'u', 0, "compress-level",		&backup->compress_level, SOURCE_FILE_STRICT}, | ||||||
| 		{'b', 0, "from-replica",		&from_replica, SOURCE_FILE_STRICT}, | 		{'b', 0, "from-replica",		&backup->from_replica, SOURCE_FILE_STRICT}, | ||||||
| 		{'s', 0, "primary-conninfo",	&backup->primary_conninfo, SOURCE_FILE_STRICT}, | 		{'s', 0, "primary-conninfo",	&backup->primary_conninfo, SOURCE_FILE_STRICT}, | ||||||
| 		{0} | 		{0} | ||||||
| 	}; | 	}; | ||||||
| @@ -578,6 +577,9 @@ readBackupControlFile(const char *path) | |||||||
| 		pfree(server_version); | 		pfree(server_version); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (compress_alg) | ||||||
|  | 		backup->compress_alg = parse_compress_alg(compress_alg); | ||||||
|  |  | ||||||
| 	return backup; | 	return backup; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -626,6 +628,48 @@ deparse_backup_mode(BackupMode mode) | |||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | CompressAlg | ||||||
|  | parse_compress_alg(const char *arg) | ||||||
|  | { | ||||||
|  | 	size_t		len; | ||||||
|  |  | ||||||
|  | 	/* Skip all spaces detected */ | ||||||
|  | 	while (isspace((unsigned char)*arg)) | ||||||
|  | 		arg++; | ||||||
|  | 	len = strlen(arg); | ||||||
|  |  | ||||||
|  | 	if (len == 0) | ||||||
|  | 		elog(ERROR, "compress algrorithm is empty"); | ||||||
|  |  | ||||||
|  | 	if (pg_strncasecmp("zlib", arg, len) == 0) | ||||||
|  | 		return ZLIB_COMPRESS; | ||||||
|  | 	else if (pg_strncasecmp("pglz", arg, len) == 0) | ||||||
|  | 		return PGLZ_COMPRESS; | ||||||
|  | 	else if (pg_strncasecmp("none", arg, len) == 0) | ||||||
|  | 		return NONE_COMPRESS; | ||||||
|  | 	else | ||||||
|  | 		elog(ERROR, "invalid compress algorithm value \"%s\"", arg); | ||||||
|  |  | ||||||
|  | 	return NOT_DEFINED_COMPRESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char* | ||||||
|  | deparse_compress_alg(int alg) | ||||||
|  | { | ||||||
|  | 	switch (alg) | ||||||
|  | 	{ | ||||||
|  | 		case NONE_COMPRESS: | ||||||
|  | 		case NOT_DEFINED_COMPRESS: | ||||||
|  | 			return "none"; | ||||||
|  | 		case ZLIB_COMPRESS: | ||||||
|  | 			return "zlib"; | ||||||
|  | 		case PGLZ_COMPRESS: | ||||||
|  | 			return "pglz"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
| /* free pgBackup object */ | /* free pgBackup object */ | ||||||
| void | void | ||||||
| pgBackupFree(void *backup) | pgBackupFree(void *backup) | ||||||
|   | |||||||
| @@ -128,6 +128,7 @@ help_pg_probackup(void) | |||||||
|  |  | ||||||
| 	printf(_("\n  %s show -B backup-dir\n"), PROGRAM_NAME); | 	printf(_("\n  %s show -B backup-dir\n"), PROGRAM_NAME); | ||||||
| 	printf(_("                 [--instance=instance_name [-i backup-id]]\n")); | 	printf(_("                 [--instance=instance_name [-i backup-id]]\n")); | ||||||
|  | 	printf(_("                 [--format=format]\n")); | ||||||
|  |  | ||||||
| 	printf(_("\n  %s delete -B backup-dir --instance=instance_name\n"), PROGRAM_NAME); | 	printf(_("\n  %s delete -B backup-dir --instance=instance_name\n"), PROGRAM_NAME); | ||||||
| 	printf(_("                 [--wal] [-i backup-id | --expired]\n")); | 	printf(_("                 [--wal] [-i backup-id | --expired]\n")); | ||||||
| @@ -362,6 +363,7 @@ help_show(void) | |||||||
| 	printf(_("  -B, --backup-path=backup-path    location of the backup storage area\n")); | 	printf(_("  -B, --backup-path=backup-path    location of the backup storage area\n")); | ||||||
| 	printf(_("      --instance=instance_name     show info about specific intstance\n")); | 	printf(_("      --instance=instance_name     show info about specific intstance\n")); | ||||||
| 	printf(_("  -i, --backup-id=backup-id        show info about specific backups\n")); | 	printf(_("  -i, --backup-id=backup-id        show info about specific backups\n")); | ||||||
|  | 	printf(_("      --format=format              show format=PLAIN|JSON\n")); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
|   | |||||||
| @@ -47,7 +47,6 @@ char	   *replication_slot = NULL; | |||||||
| /* backup options */ | /* backup options */ | ||||||
| bool		backup_logs = false; | bool		backup_logs = false; | ||||||
| bool		smooth_checkpoint; | bool		smooth_checkpoint; | ||||||
| bool		from_replica = false; |  | ||||||
| bool		is_remote_backup = false; | bool		is_remote_backup = false; | ||||||
| /* Wait timeout for WAL segment archiving */ | /* Wait timeout for WAL segment archiving */ | ||||||
| uint32		archive_timeout = 300;		/* default is 300 seconds */ | uint32		archive_timeout = 300;		/* default is 300 seconds */ | ||||||
| @@ -83,7 +82,7 @@ uint32		retention_window = 0; | |||||||
| /* compression options */ | /* compression options */ | ||||||
| CompressAlg compress_alg = NOT_DEFINED_COMPRESS; | CompressAlg compress_alg = NOT_DEFINED_COMPRESS; | ||||||
| int			compress_level = DEFAULT_COMPRESS_LEVEL; | int			compress_level = DEFAULT_COMPRESS_LEVEL; | ||||||
| bool 		compress_shortcut = false; | bool		compress_shortcut = false; | ||||||
|  |  | ||||||
| /* other options */ | /* other options */ | ||||||
| char	   *instance_name; | char	   *instance_name; | ||||||
| @@ -94,6 +93,9 @@ static char *wal_file_path; | |||||||
| static char *wal_file_name; | static char *wal_file_name; | ||||||
| static bool	file_overwrite = false; | static bool	file_overwrite = false; | ||||||
|  |  | ||||||
|  | /* show options */ | ||||||
|  | ShowFormat show_format = SHOW_PLAIN; | ||||||
|  |  | ||||||
| /* current settings */ | /* current settings */ | ||||||
| pgBackup	current; | pgBackup	current; | ||||||
| ProbackupSubcmd backup_subcmd; | ProbackupSubcmd backup_subcmd; | ||||||
| @@ -104,6 +106,7 @@ static void opt_backup_mode(pgut_option *opt, const char *arg); | |||||||
| static void opt_log_level_console(pgut_option *opt, const char *arg); | static void opt_log_level_console(pgut_option *opt, const char *arg); | ||||||
| static void opt_log_level_file(pgut_option *opt, const char *arg); | static void opt_log_level_file(pgut_option *opt, const char *arg); | ||||||
| static void opt_compress_alg(pgut_option *opt, const char *arg); | static void opt_compress_alg(pgut_option *opt, const char *arg); | ||||||
|  | static void opt_show_format(pgut_option *opt, const char *arg); | ||||||
|  |  | ||||||
| static void compress_init(void); | static void compress_init(void); | ||||||
|  |  | ||||||
| @@ -178,6 +181,8 @@ static pgut_option options[] = | |||||||
| 	{ 's', 160, "wal-file-path",		&wal_file_path,		SOURCE_CMDLINE }, | 	{ 's', 160, "wal-file-path",		&wal_file_path,		SOURCE_CMDLINE }, | ||||||
| 	{ 's', 161, "wal-file-name",		&wal_file_name,		SOURCE_CMDLINE }, | 	{ 's', 161, "wal-file-name",		&wal_file_name,		SOURCE_CMDLINE }, | ||||||
| 	{ 'b', 162, "overwrite",			&file_overwrite,	SOURCE_CMDLINE }, | 	{ 'b', 162, "overwrite",			&file_overwrite,	SOURCE_CMDLINE }, | ||||||
|  | 	/* show options */ | ||||||
|  | 	{ 'f', 170, "format",				opt_show_format,	SOURCE_CMDLINE }, | ||||||
| 	{ 0 } | 	{ 0 } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -517,49 +522,31 @@ opt_log_level_file(pgut_option *opt, const char *arg) | |||||||
| 	log_level_file = parse_log_level(arg); | 	log_level_file = parse_log_level(arg); | ||||||
| } | } | ||||||
|  |  | ||||||
| CompressAlg | static void | ||||||
| parse_compress_alg(const char *arg) | opt_show_format(pgut_option *opt, const char *arg) | ||||||
| { | { | ||||||
|  | 	const char *v = arg; | ||||||
| 	size_t		len; | 	size_t		len; | ||||||
|  |  | ||||||
| 	/* Skip all spaces detected */ | 	/* Skip all spaces detected */ | ||||||
| 	while (isspace((unsigned char)*arg)) | 	while (IsSpace(*v)) | ||||||
| 		arg++; | 		v++; | ||||||
| 	len = strlen(arg); | 	len = strlen(v); | ||||||
|  |  | ||||||
| 	if (len == 0) | 	if (len > 0) | ||||||
| 		elog(ERROR, "compress algrorithm is empty"); |  | ||||||
|  |  | ||||||
| 	if (pg_strncasecmp("zlib", arg, len) == 0) |  | ||||||
| 		return ZLIB_COMPRESS; |  | ||||||
| 	else if (pg_strncasecmp("pglz", arg, len) == 0) |  | ||||||
| 		return PGLZ_COMPRESS; |  | ||||||
| 	else if (pg_strncasecmp("none", arg, len) == 0) |  | ||||||
| 		return NONE_COMPRESS; |  | ||||||
| 	else |  | ||||||
| 		elog(ERROR, "invalid compress algorithm value \"%s\"", arg); |  | ||||||
|  |  | ||||||
| 	return NOT_DEFINED_COMPRESS; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const char* |  | ||||||
| deparse_compress_alg(int alg) |  | ||||||
| { |  | ||||||
| 	switch (alg) |  | ||||||
| 	{ | 	{ | ||||||
| 		case NONE_COMPRESS: | 		if (pg_strncasecmp("plain", v, len) == 0) | ||||||
| 		case NOT_DEFINED_COMPRESS: | 			show_format = SHOW_PLAIN; | ||||||
| 			return "none"; | 		else if (pg_strncasecmp("json", v, len) == 0) | ||||||
| 		case ZLIB_COMPRESS: | 			show_format = SHOW_JSON; | ||||||
| 			return "zlib"; | 		else | ||||||
| 		case PGLZ_COMPRESS: | 			elog(ERROR, "Invalid show format \"%s\"", arg); | ||||||
| 			return "pglz"; |  | ||||||
| 	} | 	} | ||||||
|  | 	else | ||||||
| 	return NULL; | 		elog(ERROR, "Invalid show format \"%s\"", arg); | ||||||
| } | } | ||||||
|  |  | ||||||
| void | static void | ||||||
| opt_compress_alg(pgut_option *opt, const char *arg) | opt_compress_alg(pgut_option *opt, const char *arg) | ||||||
| { | { | ||||||
| 	compress_alg = parse_compress_alg(arg); | 	compress_alg = parse_compress_alg(arg); | ||||||
| @@ -568,8 +555,8 @@ opt_compress_alg(pgut_option *opt, const char *arg) | |||||||
| /* | /* | ||||||
|  * Initialize compress and sanity checks for compress. |  * Initialize compress and sanity checks for compress. | ||||||
|  */ |  */ | ||||||
| static | static void | ||||||
| void compress_init(void) | compress_init(void) | ||||||
| { | { | ||||||
| 	/* Default algorithm is zlib */ | 	/* Default algorithm is zlib */ | ||||||
| 	if (compress_shortcut) | 	if (compress_shortcut) | ||||||
|   | |||||||
| @@ -149,6 +149,12 @@ typedef enum ProbackupSubcmd | |||||||
| 	SHOW_CONFIG | 	SHOW_CONFIG | ||||||
| } ProbackupSubcmd; | } ProbackupSubcmd; | ||||||
|  |  | ||||||
|  | typedef enum ShowFormat | ||||||
|  | { | ||||||
|  | 	SHOW_PLAIN, | ||||||
|  | 	SHOW_JSON | ||||||
|  | } ShowFormat; | ||||||
|  |  | ||||||
|  |  | ||||||
| /* special values of pgBackup fields */ | /* special values of pgBackup fields */ | ||||||
| #define INVALID_BACKUP_ID	 0    /* backup ID is not provided by user */ | #define INVALID_BACKUP_ID	 0    /* backup ID is not provided by user */ | ||||||
| @@ -214,6 +220,9 @@ typedef struct pgBackup | |||||||
| 	/* Size of WAL files in archive needed to restore this backup */ | 	/* Size of WAL files in archive needed to restore this backup */ | ||||||
| 	int64			wal_bytes; | 	int64			wal_bytes; | ||||||
|  |  | ||||||
|  | 	CompressAlg		compress_alg; | ||||||
|  | 	int				compress_level; | ||||||
|  |  | ||||||
| 	/* Fields needed for compatibility check */ | 	/* Fields needed for compatibility check */ | ||||||
| 	uint32			block_size; | 	uint32			block_size; | ||||||
| 	uint32			wal_block_size; | 	uint32			wal_block_size; | ||||||
| @@ -221,13 +230,14 @@ typedef struct pgBackup | |||||||
|  |  | ||||||
| 	char			server_version[100]; | 	char			server_version[100]; | ||||||
|  |  | ||||||
| 	bool			stream; 		/* Was this backup taken in stream mode? | 	bool			stream;			/* Was this backup taken in stream mode? | ||||||
| 									 * i.e. does it include all needed WAL files? */ | 									 * i.e. does it include all needed WAL files? */ | ||||||
|  | 	bool			from_replica;	/* Was this backup taken from replica */ | ||||||
| 	time_t			parent_backup; 	/* Identifier of the previous backup. | 	time_t			parent_backup; 	/* Identifier of the previous backup. | ||||||
| 									 * Which is basic backup for this | 									 * Which is basic backup for this | ||||||
| 									 * incremental backup. */ | 									 * incremental backup. */ | ||||||
| 	char			*primary_conninfo; /* Connection parameters of the backup | 	char		   *primary_conninfo; /* Connection parameters of the backup | ||||||
| 										* in the format suitable for recovery.conf */ | 									   * in the format suitable for recovery.conf */ | ||||||
| } pgBackup; | } pgBackup; | ||||||
|  |  | ||||||
| /* Recovery target for restore and validate subcommands */ | /* Recovery target for restore and validate subcommands */ | ||||||
| @@ -310,7 +320,6 @@ extern char	   *replication_slot; | |||||||
| /* backup options */ | /* backup options */ | ||||||
| extern bool		smooth_checkpoint; | extern bool		smooth_checkpoint; | ||||||
| extern uint32	archive_timeout; | extern uint32	archive_timeout; | ||||||
| extern bool		from_replica; |  | ||||||
| extern bool		is_remote_backup; | extern bool		is_remote_backup; | ||||||
| extern const char *master_db; | extern const char *master_db; | ||||||
| extern const char *master_host; | extern const char *master_host; | ||||||
| @@ -348,6 +357,9 @@ extern const char* deparse_compress_alg(int alg); | |||||||
| extern char *instance_name; | extern char *instance_name; | ||||||
| extern uint64 system_identifier; | extern uint64 system_identifier; | ||||||
|  |  | ||||||
|  | /* show options */ | ||||||
|  | extern ShowFormat show_format; | ||||||
|  |  | ||||||
| /* current settings */ | /* current settings */ | ||||||
| extern pgBackup current; | extern pgBackup current; | ||||||
| extern ProbackupSubcmd	backup_subcmd; | extern ProbackupSubcmd	backup_subcmd; | ||||||
|   | |||||||
							
								
								
									
										494
									
								
								src/show.c
									
									
									
									
									
								
							
							
						
						
									
										494
									
								
								src/show.c
									
									
									
									
									
								
							| @@ -3,28 +3,38 @@ | |||||||
|  * show.c: show backup information. |  * show.c: show backup information. | ||||||
|  * |  * | ||||||
|  * Portions Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION |  * Portions Copyright (c) 2009-2011, NIPPON TELEGRAPH AND TELEPHONE CORPORATION | ||||||
|  * Portions Copyright (c) 2015-2017, Postgres Professional |  * Portions Copyright (c) 2015-2018, Postgres Professional | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "pg_probackup.h" | #include "pg_probackup.h" | ||||||
|  |  | ||||||
| #include <time.h> | #include <time.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <dirent.h> | #include <dirent.h> | ||||||
| #include <sys/stat.h> | #include <sys/stat.h> | ||||||
|  |  | ||||||
|  | #include "pqexpbuffer.h" | ||||||
|  |  | ||||||
| static void show_backup_list(FILE *out, parray *backup_list); |  | ||||||
| static void show_backup_detail(FILE *out, pgBackup *backup); | static void show_instance_start(void); | ||||||
| static int do_show_instance(time_t requested_backup_id); | static void show_instance_end(void); | ||||||
|  | static void show_instance(time_t requested_backup_id, bool show_name); | ||||||
|  | static int show_backup(time_t requested_backup_id); | ||||||
|  |  | ||||||
|  | static void show_instance_plain(parray *backup_list, bool show_name); | ||||||
|  | static void show_instance_json(parray *backup_list); | ||||||
|  |  | ||||||
|  | static PQExpBufferData show_buf; | ||||||
|  | static bool first_instance = true; | ||||||
|  | static uint8 json_level = 0; | ||||||
|  |  | ||||||
| int | int | ||||||
| do_show(time_t requested_backup_id) | do_show(time_t requested_backup_id) | ||||||
| { | { | ||||||
|  | 	if (instance_name == NULL && | ||||||
| 	if (instance_name == NULL | 		requested_backup_id != INVALID_BACKUP_ID) | ||||||
| 		&& requested_backup_id != INVALID_BACKUP_ID) |  | ||||||
| 		elog(ERROR, "You must specify --instance to use --backup_id option"); | 		elog(ERROR, "You must specify --instance to use --backup_id option"); | ||||||
|  |  | ||||||
| 	if (instance_name == NULL) | 	if (instance_name == NULL) | ||||||
| @@ -38,10 +48,12 @@ do_show(time_t requested_backup_id) | |||||||
| 		join_path_components(path, backup_path, BACKUPS_DIR); | 		join_path_components(path, backup_path, BACKUPS_DIR); | ||||||
| 		dir = opendir(path); | 		dir = opendir(path); | ||||||
| 		if (dir == NULL) | 		if (dir == NULL) | ||||||
| 			elog(ERROR, "cannot open directory \"%s\": %s", path, strerror(errno)); | 			elog(ERROR, "Cannot open directory \"%s\": %s", | ||||||
|  | 				 path, strerror(errno)); | ||||||
|  |  | ||||||
| 		errno = 0; | 		show_instance_start(); | ||||||
| 		while ((dent = readdir(dir))) |  | ||||||
|  | 		while (errno = 0, (dent = readdir(dir)) != NULL) | ||||||
| 		{ | 		{ | ||||||
| 			char		child[MAXPGPATH]; | 			char		child[MAXPGPATH]; | ||||||
| 			struct stat	st; | 			struct stat	st; | ||||||
| @@ -54,73 +66,47 @@ do_show(time_t requested_backup_id) | |||||||
| 			join_path_components(child, path, dent->d_name); | 			join_path_components(child, path, dent->d_name); | ||||||
|  |  | ||||||
| 			if (lstat(child, &st) == -1) | 			if (lstat(child, &st) == -1) | ||||||
| 				elog(ERROR, "cannot stat file \"%s\": %s", child, strerror(errno)); | 				elog(ERROR, "Cannot stat file \"%s\": %s", | ||||||
|  | 					 child, strerror(errno)); | ||||||
|  |  | ||||||
| 			if (!S_ISDIR(st.st_mode)) | 			if (!S_ISDIR(st.st_mode)) | ||||||
| 				continue; | 				continue; | ||||||
|  |  | ||||||
| 			instance_name = dent->d_name; | 			instance_name = dent->d_name; | ||||||
| 			sprintf(backup_instance_path, "%s/%s/%s", backup_path, BACKUPS_DIR, instance_name); | 			sprintf(backup_instance_path, "%s/%s/%s", backup_path, BACKUPS_DIR, instance_name); | ||||||
| 			fprintf(stdout, "\nBACKUP INSTANCE '%s'\n", instance_name); |  | ||||||
| 			do_show_instance(0); | 			show_instance(INVALID_BACKUP_ID, true); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		if (errno) | ||||||
|  | 			elog(ERROR, "Cannot read directory \"%s\": %s", | ||||||
|  | 				 path, strerror(errno)); | ||||||
|  |  | ||||||
|  | 		if (closedir(dir)) | ||||||
|  | 			elog(ERROR, "Cannot close directory \"%s\": %s", | ||||||
|  | 				 path, strerror(errno)); | ||||||
|  |  | ||||||
|  | 		show_instance_end(); | ||||||
|  |  | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  | 	else if (requested_backup_id == INVALID_BACKUP_ID || | ||||||
|  | 			 show_format == SHOW_JSON) | ||||||
|  | 	{ | ||||||
|  | 		show_instance_start(); | ||||||
|  | 		show_instance(requested_backup_id, false); | ||||||
|  | 		show_instance_end(); | ||||||
|  |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 		return do_show_instance(requested_backup_id); | 		return show_backup(requested_backup_id); | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * If 'requested_backup_id' is INVALID_BACKUP_ID, show brief meta information |  | ||||||
|  * about all backups in the backup instance. |  | ||||||
|  * If valid backup id is passed, show detailed meta information |  | ||||||
|  * about specified backup. |  | ||||||
|  */ |  | ||||||
| static int |  | ||||||
| do_show_instance(time_t requested_backup_id) |  | ||||||
| { |  | ||||||
| 	if (requested_backup_id != INVALID_BACKUP_ID) |  | ||||||
| 	{ |  | ||||||
| 		pgBackup   *backup; |  | ||||||
|  |  | ||||||
| 		backup = read_backup(requested_backup_id); |  | ||||||
| 		if (backup == NULL) |  | ||||||
| 		{ |  | ||||||
| 			elog(INFO, "Requested backup \"%s\" is not found.", |  | ||||||
| 				 /* We do not need free base36enc's result, we exit anyway */ |  | ||||||
| 				 base36enc(requested_backup_id)); |  | ||||||
| 			/* This is not error */ |  | ||||||
| 			return 0; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		show_backup_detail(stdout, backup); |  | ||||||
|  |  | ||||||
| 		/* cleanup */ |  | ||||||
| 		pgBackupFree(backup); |  | ||||||
|  |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		parray *backup_list; |  | ||||||
|  |  | ||||||
| 		backup_list = catalog_get_backup_list(INVALID_BACKUP_ID); |  | ||||||
| 		if (backup_list == NULL) |  | ||||||
| 			elog(ERROR, "Failed to get backup list."); |  | ||||||
|  |  | ||||||
| 		show_backup_list(stdout, backup_list); |  | ||||||
|  |  | ||||||
| 		/* cleanup */ |  | ||||||
| 		parray_walk(backup_list, pgBackupFree); |  | ||||||
| 		parray_free(backup_list); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return 0; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| pretty_size(int64 size, char *buf, size_t len) | pretty_size(int64 size, char *buf, size_t len) | ||||||
| { | { | ||||||
| 	int exp = 0; | 	int			exp = 0; | ||||||
|  |  | ||||||
| 	/* minus means the size is invalid */ | 	/* minus means the size is invalid */ | ||||||
| 	if (size < 0) | 	if (size < 0) | ||||||
| @@ -219,16 +205,113 @@ get_parent_tli(TimeLineID child_tli) | |||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Initialize instance visualization. | ||||||
|  |  */ | ||||||
| static void | static void | ||||||
| show_backup_list(FILE *out, parray *backup_list) | show_instance_start(void) | ||||||
|  | { | ||||||
|  | 	initPQExpBuffer(&show_buf); | ||||||
|  |  | ||||||
|  | 	if (show_format == SHOW_PLAIN) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	first_instance = true; | ||||||
|  | 	json_level = 0; | ||||||
|  |  | ||||||
|  | 	appendPQExpBufferChar(&show_buf, '['); | ||||||
|  | 	json_level++; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Finalize instance visualization. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | show_instance_end(void) | ||||||
|  | { | ||||||
|  | 	if (show_format == SHOW_JSON) | ||||||
|  | 		appendPQExpBufferStr(&show_buf, "\n]\n"); | ||||||
|  |  | ||||||
|  | 	fputs(show_buf.data, stdout); | ||||||
|  | 	termPQExpBuffer(&show_buf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Show brief meta information about all backups in the backup instance. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | show_instance(time_t requested_backup_id, bool show_name) | ||||||
|  | { | ||||||
|  | 	parray	   *backup_list; | ||||||
|  |  | ||||||
|  | 	backup_list = catalog_get_backup_list(requested_backup_id); | ||||||
|  | 	if (backup_list == NULL) | ||||||
|  | 		elog(ERROR, "Failed to get backup list."); | ||||||
|  |  | ||||||
|  | 	if (show_format == SHOW_PLAIN) | ||||||
|  | 		show_instance_plain(backup_list, show_name); | ||||||
|  | 	else if (show_format == SHOW_JSON) | ||||||
|  | 		show_instance_json(backup_list); | ||||||
|  | 	else | ||||||
|  | 		elog(ERROR, "Invalid show format %d", (int) show_format); | ||||||
|  |  | ||||||
|  | 	/* cleanup */ | ||||||
|  | 	parray_walk(backup_list, pgBackupFree); | ||||||
|  | 	parray_free(backup_list); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Show detailed meta information about specified backup. | ||||||
|  |  */ | ||||||
|  | static int | ||||||
|  | show_backup(time_t requested_backup_id) | ||||||
|  | { | ||||||
|  | 	pgBackup   *backup; | ||||||
|  |  | ||||||
|  | 	backup = read_backup(requested_backup_id); | ||||||
|  | 	if (backup == NULL) | ||||||
|  | 	{ | ||||||
|  | 		elog(INFO, "Requested backup \"%s\" is not found.", | ||||||
|  | 			 /* We do not need free base36enc's result, we exit anyway */ | ||||||
|  | 			 base36enc(requested_backup_id)); | ||||||
|  | 		/* This is not error */ | ||||||
|  | 		return 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (show_format == SHOW_PLAIN) | ||||||
|  | 		pgBackupWriteControl(stdout, backup); | ||||||
|  | 	else | ||||||
|  | 		elog(ERROR, "Invalid show format %d", (int) show_format); | ||||||
|  |  | ||||||
|  | 	/* cleanup */ | ||||||
|  | 	pgBackupFree(backup); | ||||||
|  |  | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Plain output. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Show instance backups in plain format. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | show_instance_plain(parray *backup_list, bool show_name) | ||||||
| { | { | ||||||
| 	int			i; | 	int			i; | ||||||
|  |  | ||||||
|  | 	if (show_name) | ||||||
|  | 		printfPQExpBuffer(&show_buf, "\nBACKUP INSTANCE '%s'\n", instance_name); | ||||||
|  |  | ||||||
| 	/* if you add new fields here, fix the header */ | 	/* if you add new fields here, fix the header */ | ||||||
| 	/* show header */ | 	/* show header */ | ||||||
| 	fputs("============================================================================================================================================\n", out); | 	appendPQExpBufferStr(&show_buf, | ||||||
| 	fputs(" Instance    Version  ID      Recovery time           Mode    WAL      Current/Parent TLI    Time    Data   Start LSN    Stop LSN    Status \n", out); | 						 "============================================================================================================================================\n"); | ||||||
| 	fputs("============================================================================================================================================\n", out); | 	appendPQExpBufferStr(&show_buf, | ||||||
|  | 						 " Instance    Version  ID      Recovery time           Mode    WAL      Current/Parent TLI    Time    Data   Start LSN    Stop LSN    Status \n"); | ||||||
|  | 	appendPQExpBufferStr(&show_buf, | ||||||
|  | 						 "============================================================================================================================================\n"); | ||||||
|  |  | ||||||
| 	for (i = 0; i < parray_num(backup_list); i++) | 	for (i = 0; i < parray_num(backup_list); i++) | ||||||
| 	{ | 	{ | ||||||
| @@ -255,27 +338,270 @@ show_backup_list(FILE *out, parray *backup_list) | |||||||
| 		/* Get parent timeline before printing */ | 		/* Get parent timeline before printing */ | ||||||
| 		parent_tli = get_parent_tli(backup->tli); | 		parent_tli = get_parent_tli(backup->tli); | ||||||
|  |  | ||||||
| 		fprintf(out, " %-11s %-8s %-6s  %-22s  %-6s  %-7s  %3d / %-3d            %5s  %6s  %2X/%-8X  %2X/%-8X  %-8s\n", | 		appendPQExpBuffer(&show_buf, | ||||||
| 				instance_name, | 						  " %-11s %-8s %-6s  %-22s  %-6s  %-7s  %3d / %-3d            %5s  %6s  %2X/%-8X  %2X/%-8X  %-8s\n", | ||||||
| 				(backup->server_version[0] ? backup->server_version : "----"), | 						  instance_name, | ||||||
| 				base36enc(backup->start_time), | 						  (backup->server_version[0] ? backup->server_version : "----"), | ||||||
| 				timestamp, | 						  base36enc(backup->start_time), | ||||||
| 				pgBackupGetBackupMode(backup), | 						  timestamp, | ||||||
| 				backup->stream ? "STREAM": "ARCHIVE", | 						  pgBackupGetBackupMode(backup), | ||||||
| 				backup->tli, | 						  backup->stream ? "STREAM": "ARCHIVE", | ||||||
| 				parent_tli, | 						  backup->tli, | ||||||
| 				duration, | 						  parent_tli, | ||||||
| 				data_bytes_str, | 						  duration, | ||||||
| 				(uint32) (backup->start_lsn >> 32), | 						  data_bytes_str, | ||||||
| 				(uint32) backup->start_lsn, | 						  (uint32) (backup->start_lsn >> 32), | ||||||
| 				(uint32) (backup->stop_lsn >> 32), | 						  (uint32) backup->start_lsn, | ||||||
| 				(uint32) backup->stop_lsn, | 						  (uint32) (backup->stop_lsn >> 32), | ||||||
| 				status2str(backup->status)); | 						  (uint32) backup->stop_lsn, | ||||||
|  | 						  status2str(backup->status)); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Json output. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | json_add_indent(PQExpBuffer buf) | ||||||
|  | { | ||||||
|  | 	uint8		i; | ||||||
|  |  | ||||||
|  | 	if (json_level == 0) | ||||||
|  | 		return; | ||||||
|  |  | ||||||
|  | 	appendPQExpBufferChar(buf, '\n'); | ||||||
|  | 	for (i = 0; i < json_level; i++) | ||||||
|  | 		appendPQExpBufferStr(buf, "    "); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | typedef enum | ||||||
|  | { | ||||||
|  | 	JT_BEGIN_ARRAY, | ||||||
|  | 	JT_END_ARRAY, | ||||||
|  | 	JT_BEGIN_OBJECT, | ||||||
|  | 	JT_END_OBJECT | ||||||
|  | } JsonToken; | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | json_add(PQExpBuffer buf, JsonToken type) | ||||||
|  | { | ||||||
|  | 	switch (type) | ||||||
|  | 	{ | ||||||
|  | 		case JT_BEGIN_ARRAY: | ||||||
|  | 			appendPQExpBufferChar(buf, '['); | ||||||
|  | 			json_level++; | ||||||
|  | 			break; | ||||||
|  | 		case JT_END_ARRAY: | ||||||
|  | 			json_level--; | ||||||
|  | 			if (json_level == 0) | ||||||
|  | 				appendPQExpBufferChar(buf, '\n'); | ||||||
|  | 			else | ||||||
|  | 				json_add_indent(buf); | ||||||
|  | 			appendPQExpBufferChar(buf, ']'); | ||||||
|  | 			break; | ||||||
|  | 		case JT_BEGIN_OBJECT: | ||||||
|  | 			json_add_indent(buf); | ||||||
|  | 			appendPQExpBufferChar(buf, '{'); | ||||||
|  | 			json_level++; | ||||||
|  | 			break; | ||||||
|  | 		case JT_END_OBJECT: | ||||||
|  | 			json_level--; | ||||||
|  | 			if (json_level == 0) | ||||||
|  | 				appendPQExpBufferChar(buf, '\n'); | ||||||
|  | 			else | ||||||
|  | 				json_add_indent(buf); | ||||||
|  | 			appendPQExpBufferChar(buf, '}'); | ||||||
|  | 			break; | ||||||
|  | 		default: | ||||||
|  | 			break; | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| static void | static void | ||||||
| show_backup_detail(FILE *out, pgBackup *backup) | json_add_escaped(PQExpBuffer buf, const char *str) | ||||||
| { | { | ||||||
| 	pgBackupWriteControl(out, backup); | 	const char *p; | ||||||
|  |  | ||||||
|  | 	appendPQExpBufferChar(buf, '"'); | ||||||
|  | 	for (p = str; *p; p++) | ||||||
|  | 	{ | ||||||
|  | 		switch (*p) | ||||||
|  | 		{ | ||||||
|  | 			case '\b': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\b"); | ||||||
|  | 				break; | ||||||
|  | 			case '\f': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\f"); | ||||||
|  | 				break; | ||||||
|  | 			case '\n': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\n"); | ||||||
|  | 				break; | ||||||
|  | 			case '\r': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\r"); | ||||||
|  | 				break; | ||||||
|  | 			case '\t': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\t"); | ||||||
|  | 				break; | ||||||
|  | 			case '"': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\\""); | ||||||
|  | 				break; | ||||||
|  | 			case '\\': | ||||||
|  | 				appendPQExpBufferStr(buf, "\\\\"); | ||||||
|  | 				break; | ||||||
|  | 			default: | ||||||
|  | 				if ((unsigned char) *p < ' ') | ||||||
|  | 					appendPQExpBuffer(buf, "\\u%04x", (int) *p); | ||||||
|  | 				else | ||||||
|  | 					appendPQExpBufferChar(buf, *p); | ||||||
|  | 				break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	appendPQExpBufferChar(buf, '"'); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | json_add_key(PQExpBuffer buf, const char *name, bool add_comma) | ||||||
|  | { | ||||||
|  | 	if (add_comma) | ||||||
|  | 		appendPQExpBufferChar(buf, ','); | ||||||
|  | 	json_add_indent(buf); | ||||||
|  |  | ||||||
|  | 	json_add_escaped(buf, name); | ||||||
|  | 	appendPQExpBufferStr(buf, ": "); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | json_add_value(PQExpBuffer buf, const char *name, const char *value, | ||||||
|  | 			   bool add_comma) | ||||||
|  | { | ||||||
|  | 	json_add_key(buf, name, add_comma); | ||||||
|  | 	json_add_escaped(buf, value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Show instance backups in json format. | ||||||
|  |  */ | ||||||
|  | static void | ||||||
|  | show_instance_json(parray *backup_list) | ||||||
|  | { | ||||||
|  | 	int			i; | ||||||
|  | 	PQExpBuffer	buf = &show_buf; | ||||||
|  |  | ||||||
|  | 	if (!first_instance) | ||||||
|  | 		appendPQExpBufferChar(buf, ','); | ||||||
|  |  | ||||||
|  | 	/* Begin of instance object */ | ||||||
|  | 	json_add(buf, JT_BEGIN_OBJECT); | ||||||
|  |  | ||||||
|  | 	json_add_value(buf, "instance-name", instance_name, false); | ||||||
|  |  | ||||||
|  | 	json_add_key(buf, "backups", true); | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * List backups. | ||||||
|  | 	 */ | ||||||
|  | 	json_add(buf, JT_BEGIN_ARRAY); | ||||||
|  |  | ||||||
|  | 	for (i = 0; i < parray_num(backup_list); i++) | ||||||
|  | 	{ | ||||||
|  | 		pgBackup   *backup = parray_get(backup_list, i); | ||||||
|  | 		TimeLineID	parent_tli; | ||||||
|  | 		char		timestamp[100] = "----"; | ||||||
|  | 		char		duration[20] = "----"; | ||||||
|  | 		char		data_bytes_str[10] = "----"; | ||||||
|  | 		char		lsn[20]; | ||||||
|  |  | ||||||
|  | 		if (i != 0) | ||||||
|  | 			appendPQExpBufferChar(buf, ','); | ||||||
|  |  | ||||||
|  | 		json_add(buf, JT_BEGIN_OBJECT); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "id", base36enc(backup->start_time), true); | ||||||
|  |  | ||||||
|  | 		if (backup->parent_backup != 0) | ||||||
|  | 			json_add_value(buf, "parent-backup-id", | ||||||
|  | 						   base36enc(backup->parent_backup), true); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "backup-mode", pgBackupGetBackupMode(backup), false); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "wal", backup->stream ? "STREAM": "ARCHIVE", true); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "compress-alg", | ||||||
|  | 					   deparse_compress_alg(backup->compress_alg), true); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "compress-level", true); | ||||||
|  | 		appendPQExpBuffer(buf, "%d", backup->compress_level); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "from-replica", | ||||||
|  | 					   backup->from_replica ? "true" : "false", true); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "block-size", true); | ||||||
|  | 		appendPQExpBuffer(buf, "%u", backup->block_size); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "xlog-block-size", true); | ||||||
|  | 		appendPQExpBuffer(buf, "%u", backup->wal_block_size); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "checksum-version", true); | ||||||
|  | 		appendPQExpBuffer(buf, "%u", backup->checksum_version); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "server-version", backup->server_version, true); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "current-tli", true); | ||||||
|  | 		appendPQExpBuffer(buf, "%d", backup->tli); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "parent-tli", true); | ||||||
|  | 		parent_tli = get_parent_tli(backup->tli); | ||||||
|  | 		appendPQExpBuffer(buf, "%u", parent_tli); | ||||||
|  |  | ||||||
|  | 		snprintf(lsn, lengthof(lsn), "%X/%X", | ||||||
|  | 				 (uint32) (backup->start_lsn >> 32), (uint32) backup->start_lsn); | ||||||
|  | 		json_add_value(buf, "start-lsn", lsn, true); | ||||||
|  |  | ||||||
|  | 		snprintf(lsn, lengthof(lsn), "%X/%X", | ||||||
|  | 				 (uint32) (backup->stop_lsn >> 32), (uint32) backup->stop_lsn); | ||||||
|  | 		json_add_value(buf, "stop-lsn", lsn, true); | ||||||
|  |  | ||||||
|  | 		time2iso(timestamp, lengthof(timestamp), backup->start_time); | ||||||
|  | 		json_add_value(buf, "start-time", timestamp, true); | ||||||
|  |  | ||||||
|  | 		time2iso(timestamp, lengthof(timestamp), backup->end_time); | ||||||
|  | 		json_add_value(buf, "end-time", timestamp, true); | ||||||
|  |  | ||||||
|  | 		json_add_key(buf, "recovery-xid", true); | ||||||
|  | 		appendPQExpBuffer(buf, XID_FMT, backup->recovery_xid); | ||||||
|  |  | ||||||
|  | 		time2iso(timestamp, lengthof(timestamp), backup->recovery_time); | ||||||
|  | 		json_add_value(buf, "recovery-time", timestamp, true); | ||||||
|  |  | ||||||
|  | 		pretty_size(backup->data_bytes, data_bytes_str, | ||||||
|  | 					lengthof(data_bytes_str)); | ||||||
|  | 		json_add_value(buf, "data-bytes", data_bytes_str, true); | ||||||
|  |  | ||||||
|  | 		pretty_size(backup->wal_bytes, data_bytes_str, | ||||||
|  | 					lengthof(data_bytes_str)); | ||||||
|  | 		json_add_value(buf, "wal-bytes", data_bytes_str, true); | ||||||
|  |  | ||||||
|  | 		if (backup->end_time != (time_t) 0) | ||||||
|  | 		{ | ||||||
|  | 			snprintf(duration, lengthof(duration), "%.*lfs",  0, | ||||||
|  | 					 difftime(backup->end_time, backup->start_time)); | ||||||
|  | 			json_add_value(buf, "time", duration, true); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (backup->primary_conninfo) | ||||||
|  | 			json_add_value(buf, "primary_conninfo", backup->primary_conninfo, true); | ||||||
|  |  | ||||||
|  | 		json_add_value(buf, "status", status2str(backup->status), true); | ||||||
|  |  | ||||||
|  | 		json_add(buf, JT_END_OBJECT); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* End of backups */ | ||||||
|  | 	json_add(buf, JT_END_ARRAY); | ||||||
|  |  | ||||||
|  | 	/* End of instance object */ | ||||||
|  | 	json_add(buf, JT_END_OBJECT); | ||||||
|  |  | ||||||
|  | 	first_instance = false; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								src/util.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/util.c
									
									
									
									
									
								
							| @@ -176,8 +176,8 @@ uint32 | |||||||
| get_data_checksum_version(bool safe) | get_data_checksum_version(bool safe) | ||||||
| { | { | ||||||
| 	ControlFileData ControlFile; | 	ControlFileData ControlFile; | ||||||
| 	char       *buffer; | 	char	   *buffer; | ||||||
| 	size_t      size; | 	size_t		size; | ||||||
|  |  | ||||||
| 	/* First fetch file... */ | 	/* First fetch file... */ | ||||||
| 	buffer = slurpFile(pgdata, "global/pg_control", &size, safe); | 	buffer = slurpFile(pgdata, "global/pg_control", &size, safe); | ||||||
| @@ -310,10 +310,19 @@ pgBackup_init(pgBackup *backup) | |||||||
| 	backup->end_time = (time_t) 0; | 	backup->end_time = (time_t) 0; | ||||||
| 	backup->recovery_xid = 0; | 	backup->recovery_xid = 0; | ||||||
| 	backup->recovery_time = (time_t) 0; | 	backup->recovery_time = (time_t) 0; | ||||||
|  |  | ||||||
| 	backup->data_bytes = BYTES_INVALID; | 	backup->data_bytes = BYTES_INVALID; | ||||||
|  | 	backup->wal_bytes = BYTES_INVALID; | ||||||
|  |  | ||||||
|  | 	backup->compress_alg = NOT_DEFINED_COMPRESS; | ||||||
|  | 	backup->compress_level = 0; | ||||||
|  |  | ||||||
| 	backup->block_size = BLCKSZ; | 	backup->block_size = BLCKSZ; | ||||||
| 	backup->wal_block_size = XLOG_BLCKSZ; | 	backup->wal_block_size = XLOG_BLCKSZ; | ||||||
|  | 	backup->checksum_version = 0; | ||||||
|  |  | ||||||
| 	backup->stream = false; | 	backup->stream = false; | ||||||
|  | 	backup->from_replica = false; | ||||||
| 	backup->parent_backup = 0; | 	backup->parent_backup = 0; | ||||||
| 	backup->primary_conninfo = NULL; | 	backup->primary_conninfo = NULL; | ||||||
| 	backup->server_version[0] = '\0'; | 	backup->server_version[0] = '\0'; | ||||||
|   | |||||||
| @@ -59,7 +59,7 @@ typedef enum pgut_optsrc | |||||||
| typedef struct pgut_option | typedef struct pgut_option | ||||||
| { | { | ||||||
| 	char		type; | 	char		type; | ||||||
| 	char		sname;		/* short name */ | 	uint8		sname;		/* short name */ | ||||||
| 	const char *lname;		/* long name */ | 	const char *lname;		/* long name */ | ||||||
| 	void	   *var;		/* pointer to variable */ | 	void	   *var;		/* pointer to variable */ | ||||||
| 	pgut_optsrc	allowed;	/* allowed source */ | 	pgut_optsrc	allowed;	/* allowed source */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user