1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2024-12-12 11:45:24 +02:00

[Issue #272] fix DST time skew, store backup metadata timestamps in UTC

This commit is contained in:
Grigory Smolkin 2020-12-02 11:15:21 +03:00
parent 1cf233d3a0
commit 6c21833a17
9 changed files with 78 additions and 55 deletions

View File

@ -133,7 +133,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
pg_ptrack_clear(backup_conn, nodeInfo->ptrack_version_num);
/* notify start of backup to PostgreSQL server */
time2iso(label, lengthof(label), current.start_time);
time2iso(label, lengthof(label), current.start_time, false);
strncat(label, " with pg_probackup", lengthof(label) -
strlen(" with pg_probackup"));

View File

@ -789,7 +789,7 @@ catalog_get_backup_list(const char *instance_name, time_t requested_backup_id)
}
else if (strcmp(base36enc(backup->start_time), data_ent->d_name) != 0)
{
elog(VERBOSE, "backup ID in control file \"%s\" doesn't match name of the backup folder \"%s\"",
elog(WARNING, "backup ID in control file \"%s\" doesn't match name of the backup folder \"%s\"",
base36enc(backup->start_time), backup_conf_path);
}
@ -1952,7 +1952,7 @@ pin_backup(pgBackup *target_backup, pgSetBackupParams *set_backup_params)
{
char expire_timestamp[100];
time2iso(expire_timestamp, lengthof(expire_timestamp), target_backup->expire_time);
time2iso(expire_timestamp, lengthof(expire_timestamp), target_backup->expire_time, false);
elog(INFO, "Backup %s is pinned until '%s'", base36enc(target_backup->start_time),
expire_timestamp);
}
@ -2003,7 +2003,7 @@ add_note(pgBackup *target_backup, char *note)
* Write information about backup.in to stream "out".
*/
void
pgBackupWriteControl(FILE *out, pgBackup *backup)
pgBackupWriteControl(FILE *out, pgBackup *backup, bool utc)
{
char timestamp[100];
@ -2035,27 +2035,27 @@ pgBackupWriteControl(FILE *out, pgBackup *backup)
(uint32) (backup->stop_lsn >> 32),
(uint32) backup->stop_lsn);
time2iso(timestamp, lengthof(timestamp), backup->start_time);
time2iso(timestamp, lengthof(timestamp), backup->start_time, utc);
fio_fprintf(out, "start-time = '%s'\n", timestamp);
if (backup->merge_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->merge_time);
time2iso(timestamp, lengthof(timestamp), backup->merge_time, utc);
fio_fprintf(out, "merge-time = '%s'\n", timestamp);
}
if (backup->end_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->end_time);
time2iso(timestamp, lengthof(timestamp), backup->end_time, utc);
fio_fprintf(out, "end-time = '%s'\n", timestamp);
}
fio_fprintf(out, "recovery-xid = " XID_FMT "\n", backup->recovery_xid);
if (backup->recovery_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
time2iso(timestamp, lengthof(timestamp), backup->recovery_time, utc);
fio_fprintf(out, "recovery-time = '%s'\n", timestamp);
}
if (backup->expire_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->expire_time);
time2iso(timestamp, lengthof(timestamp), backup->expire_time, utc);
fio_fprintf(out, "expire-time = '%s'\n", timestamp);
}
@ -2109,7 +2109,7 @@ pgBackupWriteControl(FILE *out, pgBackup *backup)
void
write_backup(pgBackup *backup, bool strict)
{
FILE *fp_out = NULL;
FILE *fp = NULL;
char path[MAXPGPATH];
char path_temp[MAXPGPATH];
char buf[8192];
@ -2117,8 +2117,8 @@ write_backup(pgBackup *backup, bool strict)
join_path_components(path, backup->root_dir, BACKUP_CONTROL_FILE);
snprintf(path_temp, sizeof(path_temp), "%s.tmp", path);
fp_out = fopen(path_temp, PG_BINARY_W);
if (fp_out == NULL)
fp = fopen(path_temp, PG_BINARY_W);
if (fp == NULL)
elog(ERROR, "Cannot open control file \"%s\": %s",
path_temp, strerror(errno));
@ -2126,12 +2126,12 @@ write_backup(pgBackup *backup, bool strict)
elog(ERROR, "Cannot change mode of \"%s\": %s", path_temp,
strerror(errno));
setvbuf(fp_out, buf, _IOFBF, sizeof(buf));
setvbuf(fp, buf, _IOFBF, sizeof(buf));
pgBackupWriteControl(fp_out, backup);
pgBackupWriteControl(fp, backup, true);
/* Ignore 'out of space' error in lax mode */
if (fflush(fp_out) != 0)
if (fflush(fp) != 0)
{
int elevel = ERROR;
int save_errno = errno;
@ -2144,17 +2144,18 @@ write_backup(pgBackup *backup, bool strict)
if (!strict && (save_errno == ENOSPC))
{
fclose(fp_out);
fclose(fp);
fio_unlink(path_temp, FIO_BACKUP_HOST);
return;
}
}
if (fsync(fileno(fp_out)) < 0)
elog(ERROR, "Cannot sync control file \"%s\": %s",
if (fclose(fp) != 0)
elog(ERROR, "Cannot close control file \"%s\": %s",
path_temp, strerror(errno));
if (fclose(fp_out) != 0)
elog(ERROR, "Cannot close control file \"%s\": %s",
if (fio_sync(path_temp, FIO_BACKUP_HOST) < 0)
elog(ERROR, "Cannot sync control file \"%s\": %s",
path_temp, strerror(errno));
if (rename(path_temp, path) < 0)

View File

@ -316,7 +316,7 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
(backup->expire_time > current_time))
{
char expire_timestamp[100];
time2iso(expire_timestamp, lengthof(expire_timestamp), backup->expire_time);
time2iso(expire_timestamp, lengthof(expire_timestamp), backup->expire_time, false);
elog(LOG, "Backup %s is pinned until '%s', retain",
base36enc(backup->start_time), expire_timestamp);
@ -740,7 +740,7 @@ delete_backup_files(pgBackup *backup)
return;
}
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
time2iso(timestamp, lengthof(timestamp), backup->recovery_time, false);
elog(INFO, "Delete: %s %s",
base36enc(backup->start_time), timestamp);

View File

@ -480,7 +480,7 @@ validate_wal(pgBackup *backup, const char *archivedir,
last_rec.rec_xid = backup->recovery_xid;
last_rec.rec_lsn = backup->stop_lsn;
time2iso(last_timestamp, lengthof(last_timestamp), backup->recovery_time);
time2iso(last_timestamp, lengthof(last_timestamp), backup->recovery_time, false);
if ((TransactionIdIsValid(target_xid) && target_xid == last_rec.rec_xid)
|| (target_time != 0 && backup->recovery_time >= target_time)
@ -493,7 +493,7 @@ validate_wal(pgBackup *backup, const char *archivedir,
InvalidXLogRecPtr, true, validateXLogRecord, &last_rec, true);
if (last_rec.rec_time > 0)
time2iso(last_timestamp, lengthof(last_timestamp),
timestamptz_to_time_t(last_rec.rec_time));
timestamptz_to_time_t(last_rec.rec_time), false);
/* There are all needed WAL records */
if (all_wal)
@ -508,7 +508,7 @@ validate_wal(pgBackup *backup, const char *archivedir,
(uint32) (last_rec.rec_lsn >> 32), (uint32) last_rec.rec_lsn);
if (target_time > 0)
time2iso(target_timestamp, lengthof(target_timestamp), target_time);
time2iso(target_timestamp, lengthof(target_timestamp), target_time, false);
if (TransactionIdIsValid(target_xid) && target_time != 0)
elog(ERROR, "Not enough WAL records to time %s and xid " XID_FMT,
target_timestamp, target_xid);

View File

@ -394,10 +394,9 @@ struct pgBackup
TimeLineID tli; /* timeline of start and stop backup lsns */
XLogRecPtr start_lsn; /* backup's starting transaction log location */
XLogRecPtr stop_lsn; /* backup's finishing transaction log location */
time_t start_time; /* since this moment backup has status
* BACKUP_STATUS_RUNNING */
time_t merge_dest_backup; /* start_time of incremental backup,
* this backup is merging with.
time_t start_time; /* UTC time of backup creation */
time_t merge_dest_backup; /* start_time of incremental backup with
* which this backup is merging with.
* Only available for FULL backups
* with MERGING or MERGED statuses */
time_t merge_time; /* the moment when merge was started or 0 */
@ -892,7 +891,7 @@ extern void do_set_backup(const char *instance_name, time_t backup_id,
extern void pin_backup(pgBackup *target_backup,
pgSetBackupParams *set_backup_params);
extern void add_note(pgBackup *target_backup, char *note);
extern void pgBackupWriteControl(FILE *out, pgBackup *backup);
extern void pgBackupWriteControl(FILE *out, pgBackup *backup, bool utc);
extern void write_backup_filelist(pgBackup *backup, parray *files,
const char *root, parray *external_list, bool sync);
@ -1081,7 +1080,7 @@ extern void set_min_recovery_point(pgFile *file, const char *backup_path,
extern void copy_pgcontrol_file(const char *from_fullpath, fio_location from_location,
const char *to_fullpath, fio_location to_location, pgFile *file);
extern void time2iso(char *buf, size_t len, time_t time);
extern void time2iso(char *buf, size_t len, time_t time, bool utc);
extern const char *status2str(BackupStatus status);
extern BackupStatus str2status(const char *status);
extern const char *base36enc(long unsigned int value);

View File

@ -643,7 +643,7 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
time_t start_time, end_time;
/* Preparations for actual restoring */
time2iso(timestamp, lengthof(timestamp), dest_backup->start_time);
time2iso(timestamp, lengthof(timestamp), dest_backup->start_time, false);
elog(INFO, "Restoring the database from backup at %s", timestamp);
dest_files = get_backup_filelist(dest_backup, true);
@ -1465,7 +1465,7 @@ pg12_recovery_config(pgBackup *backup, bool add_include)
{
char current_time_str[100];
time2iso(current_time_str, lengthof(current_time_str), current_time);
time2iso(current_time_str, lengthof(current_time_str), current_time, false);
snprintf(postgres_auto_path, lengthof(postgres_auto_path),
"%s/postgresql.auto.conf", instance_config.pgdata);

View File

@ -374,12 +374,12 @@ print_backup_json_object(PQExpBuffer buf, pgBackup *backup)
(uint32) (backup->stop_lsn >> 32), (uint32) backup->stop_lsn);
json_add_value(buf, "stop-lsn", lsn, json_level, true);
time2iso(timestamp, lengthof(timestamp), backup->start_time);
time2iso(timestamp, lengthof(timestamp), backup->start_time, false);
json_add_value(buf, "start-time", timestamp, json_level, true);
if (backup->end_time)
{
time2iso(timestamp, lengthof(timestamp), backup->end_time);
time2iso(timestamp, lengthof(timestamp), backup->end_time, false);
json_add_value(buf, "end-time", timestamp, json_level, true);
}
@ -388,13 +388,13 @@ print_backup_json_object(PQExpBuffer buf, pgBackup *backup)
if (backup->recovery_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->recovery_time);
time2iso(timestamp, lengthof(timestamp), backup->recovery_time, false);
json_add_value(buf, "recovery-time", timestamp, json_level, true);
}
if (backup->expire_time > 0)
{
time2iso(timestamp, lengthof(timestamp), backup->expire_time);
time2iso(timestamp, lengthof(timestamp), backup->expire_time, false);
json_add_value(buf, "expire-time", timestamp, json_level, true);
}
@ -482,7 +482,7 @@ show_backup(const char *instance_name, time_t requested_backup_id)
}
if (show_format == SHOW_PLAIN)
pgBackupWriteControl(stdout, backup);
pgBackupWriteControl(stdout, backup, false);
else
elog(ERROR, "Invalid show format %d", (int) show_format);
@ -550,7 +550,7 @@ show_instance_plain(const char *instance_name, parray *backup_list, bool show_na
/* Recovery Time */
if (backup->recovery_time != (time_t) 0)
time2iso(row->recovery_time, lengthof(row->recovery_time),
backup->recovery_time);
backup->recovery_time, false);
else
StrNCpy(row->recovery_time, "----", sizeof(row->recovery_time));
widths[cur] = Max(widths[cur], strlen(row->recovery_time));

View File

@ -679,7 +679,7 @@ option_get_value(ConfigOption *opt)
if (t > 0)
{
timestamp = palloc(100);
time2iso(timestamp, 100, t);
time2iso(timestamp, 100, t, false);
}
else
timestamp = palloc0(1 /* just null termination */);
@ -1111,6 +1111,8 @@ parse_time(const char *value, time_t *result, bool utc_default)
struct tm tm;
char junk[2];
char *local_tz = getenv("TZ");
/* tmp = replace( value, !isalnum, ' ' ) */
tmp = pgut_malloc(strlen(value) + + 1);
len = 0;
@ -1221,26 +1223,27 @@ parse_time(const char *value, time_t *result, bool utc_default)
/* determine whether Daylight Saving Time is in effect */
tm.tm_isdst = -1;
/* set timezone to UTC */
setenv("TZ", "UTC", 1);
/* convert time to utc unix time */
*result = mktime(&tm);
/* return old timezone back if any */
if (local_tz)
setenv("TZ", local_tz, 1);
else
unsetenv("TZ");
/* adjust time zone */
if (tz_set || utc_default)
{
time_t ltime = time(NULL);
struct tm *ptm = gmtime(&ltime);
time_t gmt = mktime(ptm);
time_t offset;
/* UTC time */
*result -= tz;
/* Get local time */
ptm = localtime(&ltime);
offset = ltime - gmt + (ptm->tm_isdst ? 3600 : 0);
*result += offset;
}
pg_free(local_tz);
return true;
}
@ -1462,14 +1465,32 @@ convert_from_base_unit_u(uint64 base_value, int base_unit,
* Convert time_t value to ISO-8601 format string. Always set timezone offset.
*/
void
time2iso(char *buf, size_t len, time_t time)
time2iso(char *buf, size_t len, time_t time, bool utc)
{
struct tm *ptm = gmtime(&time);
time_t gmt = mktime(ptm);
struct tm *ptm = NULL;
time_t gmt;
time_t offset;
char *ptr = buf;
char *local_tz = getenv("TZ");
/* set timezone to UTC if requested */
if (utc)
setenv("TZ", "UTC", 1);
ptm = gmtime(&time);
gmt = mktime(ptm);
ptm = localtime(&time);
if (utc)
{
/* return old timezone back if any */
if (local_tz)
setenv("TZ", local_tz, 1);
else
unsetenv("TZ");
}
/* adjust timezone offset */
offset = time - gmt + (ptm->tm_isdst ? 3600 : 0);
strftime(ptr, len, "%Y-%m-%d %H:%M:%S", ptm);
@ -1485,4 +1506,6 @@ time2iso(char *buf, size_t len, time_t time)
snprintf(ptr, len - (ptr - buf), ":%02d",
abs((int) offset % SECS_PER_HOUR) / SECS_PER_MINUTE);
}
pg_free(local_tz);
}

View File

@ -96,7 +96,7 @@ extern bool parse_int(const char *value, int *result, int flags,
const char **hintmsg);
extern bool parse_lsn(const char *value, XLogRecPtr *result);
extern void time2iso(char *buf, size_t len, time_t time);
extern void time2iso(char *buf, size_t len, time_t time, bool utc);
extern void convert_from_base_unit(int64 base_value, int base_unit,
int64 *value, const char **unit);