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:
parent
1cf233d3a0
commit
6c21833a17
@ -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"));
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
12
src/show.c
12
src/show.c
@ -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));
|
||||
|
@ -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(<ime);
|
||||
time_t gmt = mktime(ptm);
|
||||
time_t offset;
|
||||
|
||||
/* UTC time */
|
||||
*result -= tz;
|
||||
|
||||
/* Get local time */
|
||||
ptm = localtime(<ime);
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user