Skip to content

Commit 38726e7

Browse files
committed
Merge branch 'master' into stable
2 parents e90527d + 7a0cc9a commit 38726e7

18 files changed

+522
-224
lines changed

src/backup.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,11 +596,11 @@ do_backup_instance(void)
596596
{
597597
XLogRecPtr ptrack_lsn = get_last_ptrack_lsn();
598598

599-
if (ptrack_lsn > prev_backup->stop_lsn)
599+
if (ptrack_lsn > prev_backup->stop_lsn || ptrack_lsn == InvalidXLogRecPtr)
600600
{
601-
elog(ERROR, "LSN from ptrack_control %lx differs from LSN of previous backup %lx.\n"
601+
elog(ERROR, "LSN from ptrack_control %lx differs from STOP LSN of previous backup %lx.\n"
602602
"Create new full backup before an incremental one.",
603-
ptrack_lsn, prev_backup->start_lsn);
603+
ptrack_lsn, prev_backup->stop_lsn);
604604
}
605605
parray_qsort(backup_files_list, pgFileComparePath);
606606
make_pagemap_from_ptrack(backup_files_list);
@@ -782,14 +782,17 @@ do_backup(void)
782782
current.stream = stream_wal;
783783

784784
is_ptrack_support = pg_ptrack_support();
785+
if (is_ptrack_support)
786+
{
787+
is_ptrack_enable = pg_ptrack_enable();
788+
}
785789

786790
if (current.backup_mode == BACKUP_MODE_DIFF_PTRACK)
787791
{
788792
if (!is_ptrack_support)
789793
elog(ERROR, "This PostgreSQL instance does not support ptrack");
790794
else
791795
{
792-
is_ptrack_enable = pg_ptrack_enable();
793796
if(!is_ptrack_enable)
794797
elog(ERROR, "Ptrack is disabled");
795798
}
@@ -1060,16 +1063,23 @@ pg_ptrack_support(void)
10601063
PGresult *res_db;
10611064

10621065
res_db = pgut_execute(backup_conn,
1063-
"SELECT proname FROM pg_proc WHERE proname='pg_ptrack_clear'",
1066+
"SELECT ptrack_version()",
10641067
0, NULL);
10651068

10661069
if (PQntuples(res_db) == 0)
10671070
{
10681071
PQclear(res_db);
10691072
return false;
10701073
}
1071-
PQclear(res_db);
10721074

1075+
/* Now we support only ptrack version 1.3 */
1076+
if (strcmp(PQgetvalue(res_db, 0, 0), "1.3") != 0)
1077+
{
1078+
PQclear(res_db);
1079+
return false;
1080+
}
1081+
1082+
PQclear(res_db);
10731083
return true;
10741084
}
10751085

@@ -1546,13 +1556,13 @@ pg_stop_backup(pgBackup *backup)
15461556
*/
15471557
sent = pgut_send(conn,
15481558
"SELECT *, txid_snapshot_xmax(txid_current_snapshot()),"
1549-
" current_timestamp(0)::timestamp"
1559+
" current_timestamp(0)::timestamptz"
15501560
" FROM pg_stop_backup(false)",
15511561
0, NULL, WARNING);
15521562
else
15531563
sent = pgut_send(conn,
15541564
"SELECT *, txid_snapshot_xmax(txid_current_snapshot()),"
1555-
" current_timestamp(0)::timestamp"
1565+
" current_timestamp(0)::timestamptz"
15561566
" FROM pg_stop_backup()",
15571567
0, NULL, WARNING);
15581568

src/catalog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ pgBackupCreateDir(pgBackup *backup)
381381
void
382382
pgBackupWriteControl(FILE *out, pgBackup *backup)
383383
{
384-
char timestamp[20];
384+
char timestamp[100];
385385

386386
fprintf(out, "#Configuration\n");
387387
fprintf(out, "backup-mode = %s\n", pgBackupGetBackupMode(backup));

src/delete.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ pgBackupDeleteFiles(pgBackup *backup)
223223
size_t i;
224224
char *backup_id;
225225
char path[MAXPGPATH];
226-
char timestamp[20];
226+
char timestamp[100];
227227
parray *files;
228228

229229
/*
@@ -428,4 +428,4 @@ do_delete_instance(void)
428428

429429
elog(INFO, "Instance '%s' successfully deleted", instance_name);
430430
return 0;
431-
}
431+
}

src/pg_probackup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include <sys/stat.h>
1818
#include <unistd.h>
1919

20-
const char *PROGRAM_VERSION = "2.0.6";
20+
const char *PROGRAM_VERSION = "2.0.8";
2121
const char *PROGRAM_URL = "https://github.com/postgrespro/pg_probackup";
2222
const char *PROGRAM_EMAIL = "https://github.com/postgrespro/pg_probackup/issues";
2323

src/restore.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ create_recovery_conf(time_t backup_id,
720720
PROGRAM_VERSION);
721721
fprintf(fp, "restore_command = 'pg_probackup archive-get -B %s --instance %s --wal-file-path %%p --wal-file-name %%f'\n",
722722
backup_path, instance_name);
723+
fprintf(fp, "recovery_target_action = 'promote'\n");
723724

724725
if (target_time)
725726
fprintf(fp, "recovery_target_time = '%s'\n", target_time);
@@ -736,7 +737,6 @@ create_recovery_conf(time_t backup_id,
736737
* replayed.
737738
*/
738739
fprintf(fp, "recovery_target = 'immediate'\n");
739-
fprintf(fp, "recovery_target_action = 'promote'\n");
740740
}
741741

742742
if (target_inclusive)

src/show.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,16 @@ show_backup_list(FILE *out, parray *backup_list)
226226

227227
/* if you add new fields here, fix the header */
228228
/* show header */
229-
fputs("===============================================================================================================================\n", out);
230-
fputs(" Instance ID Recovery time Mode WAL Current/Parent TLI Time Data Start LSN Stop LSN Status \n", out);
231-
fputs("===============================================================================================================================\n", out);
229+
fputs("==================================================================================================================================\n", out);
230+
fputs(" Instance ID Recovery time Mode WAL Current/Parent TLI Time Data Start LSN Stop LSN Status\n", out);
231+
fputs("==================================================================================================================================\n", out);
232232

233233
for (i = 0; i < parray_num(backup_list); i++)
234234
{
235235
pgBackup *backup = parray_get(backup_list, i);
236236
TimeLineID parent_tli;
237237
char *backup_id;
238-
char timestamp[20] = "----";
238+
char timestamp[100] = "----";
239239
char duration[20] = "----";
240240
char data_bytes_str[10] = "----";
241241

src/util.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,29 @@ get_data_checksum_version(bool safe)
144144
void
145145
time2iso(char *buf, size_t len, time_t time)
146146
{
147-
struct tm *tm = localtime(&time);
147+
struct tm *ptm = gmtime(&time);
148+
time_t gmt = mktime(ptm);
149+
time_t offset;
148150

149-
strftime(buf, len, "%Y-%m-%d %H:%M:%S", tm);
151+
ptm = localtime(&time);
152+
offset = time - gmt + (ptm->tm_isdst ? 3600 : 0);
153+
154+
strftime(buf, len, "%Y-%m-%d %H:%M:%S", ptm);
155+
156+
if (offset != 0)
157+
{
158+
buf += strlen(buf);
159+
sprintf(buf, "%c%02d",
160+
(offset >= 0) ? '+' : '-',
161+
abs((int) offset) / SECS_PER_HOUR);
162+
163+
if (abs((int) offset) % SECS_PER_HOUR != 0)
164+
{
165+
buf += strlen(buf);
166+
sprintf(buf, ":%02d",
167+
abs((int) offset % SECS_PER_HOUR) / SECS_PER_MINUTE);
168+
}
169+
}
150170
}
151171

152172
/* copied from timestamp.c */

src/utils/logger.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
*
33
* logger.h: - prototypes of logger functions.
44
*
5-
* Portions Copyright (c) 2017-2017, Postgres Professional
5+
* Copyright (c) 2017-2017, Postgres Professional
66
*
77
*-------------------------------------------------------------------------
88
*/

src/utils/pgut.c

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
#endif
2929
#endif
3030

31+
#define MAX_TZDISP_HOUR 15 /* maximum allowed hour part */
32+
#define SECS_PER_MINUTE 60
33+
#define MINS_PER_HOUR 60
34+
3135
const char *PROGRAM_NAME = NULL;
3236

3337
const char *pgut_dbname = NULL;
@@ -496,19 +500,91 @@ parse_uint64(const char *value, uint64 *result)
496500
* Convert ISO-8601 format string to time_t value.
497501
*/
498502
bool
499-
parse_time(const char *value, time_t *time)
503+
parse_time(const char *value, time_t *result)
500504
{
501505
size_t len;
506+
int fields_num,
507+
tz = 0,
508+
i;
502509
char *tmp;
503-
int i;
504510
struct tm tm;
505511
char junk[2];
506512

507513
/* tmp = replace( value, !isalnum, ' ' ) */
508514
tmp = pgut_malloc(strlen(value) + + 1);
509515
len = 0;
510-
for (i = 0; value[i]; i++)
511-
tmp[len++] = (IsAlnum(value[i]) ? value[i] : ' ');
516+
fields_num = 1;
517+
518+
while (*value)
519+
{
520+
if (IsAlnum(*value))
521+
{
522+
tmp[len++] = *value;
523+
value++;
524+
}
525+
else if (fields_num < 6)
526+
{
527+
fields_num++;
528+
tmp[len++] = ' ';
529+
value++;
530+
}
531+
/* timezone field is 7th */
532+
else if ((*value == '-' || *value == '+') && fields_num == 6)
533+
{
534+
int hr,
535+
min,
536+
sec = 0;
537+
char *cp;
538+
539+
errno = 0;
540+
hr = strtol(value + 1, &cp, 10);
541+
if ((value + 1) == cp || errno == ERANGE)
542+
return false;
543+
544+
/* explicit delimiter? */
545+
if (*cp == ':')
546+
{
547+
errno = 0;
548+
min = strtol(cp + 1, &cp, 10);
549+
if (errno == ERANGE)
550+
return false;
551+
if (*cp == ':')
552+
{
553+
errno = 0;
554+
sec = strtol(cp + 1, &cp, 10);
555+
if (errno == ERANGE)
556+
return false;
557+
}
558+
}
559+
/* otherwise, might have run things together... */
560+
else if (*cp == '\0' && strlen(value) > 3)
561+
{
562+
min = hr % 100;
563+
hr = hr / 100;
564+
/* we could, but don't, support a run-together hhmmss format */
565+
}
566+
else
567+
min = 0;
568+
569+
/* Range-check the values; see notes in datatype/timestamp.h */
570+
if (hr < 0 || hr > MAX_TZDISP_HOUR)
571+
return false;
572+
if (min < 0 || min >= MINS_PER_HOUR)
573+
return false;
574+
if (sec < 0 || sec >= SECS_PER_MINUTE)
575+
return false;
576+
577+
tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
578+
if (*value == '-')
579+
tz = -tz;
580+
581+
fields_num++;
582+
value = cp;
583+
}
584+
/* wrong format */
585+
else if (!IsSpace(*value))
586+
return false;
587+
}
512588
tmp[len] = '\0';
513589

514590
/* parse for "YYYY-MM-DD HH:MI:SS" */
@@ -540,7 +616,25 @@ parse_time(const char *value, time_t *time)
540616
/* determine whether Daylight Saving Time is in effect */
541617
tm.tm_isdst = -1;
542618

543-
*time = mktime(&tm);
619+
*result = mktime(&tm);
620+
621+
/* adjust time zone */
622+
if (tz != 0)
623+
{
624+
time_t ltime = time(NULL);
625+
struct tm *ptm = gmtime(&ltime);
626+
time_t gmt = mktime(ptm);
627+
time_t offset;
628+
629+
/* UTC time */
630+
*result -= tz;
631+
632+
/* Get local time */
633+
ptm = localtime(&ltime);
634+
offset = ltime - gmt + (ptm->tm_isdst ? 3600 : 0);
635+
636+
*result += offset;
637+
}
544638

545639
return true;
546640
}

src/utils/pgut.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ extern bool parse_int32(const char *value, int32 *result);
195195
extern bool parse_uint32(const char *value, uint32 *result);
196196
extern bool parse_int64(const char *value, int64 *result);
197197
extern bool parse_uint64(const char *value, uint64 *result);
198-
extern bool parse_time(const char *value, time_t *time);
198+
extern bool parse_time(const char *value, time_t *result);
199199
extern bool parse_int(const char *value, int *result, int flags,
200200
const char **hintmsg);
201201

tests/__init__.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,31 @@
1111

1212
def load_tests(loader, tests, pattern):
1313
suite = unittest.TestSuite()
14-
# suite.addTests(loader.loadTestsFromModule(init_test))
15-
# suite.addTests(loader.loadTestsFromModule(option_test))
16-
# suite.addTests(loader.loadTestsFromModule(show_test))
17-
# suite.addTests(loader.loadTestsFromModule(backup_test))
18-
# suite.addTests(loader.loadTestsFromModule(delete_test))
19-
# suite.addTests(loader.loadTestsFromModule(restore_test))
20-
# suite.addTests(loader.loadTestsFromModule(validate_test))
21-
# suite.addTests(loader.loadTestsFromModule(retention_test))
14+
suite.addTests(loader.loadTestsFromModule(init_test))
15+
suite.addTests(loader.loadTestsFromModule(option_test))
16+
suite.addTests(loader.loadTestsFromModule(show_test))
17+
suite.addTests(loader.loadTestsFromModule(backup_test))
18+
suite.addTests(loader.loadTestsFromModule(delete_test))
19+
suite.addTests(loader.loadTestsFromModule(restore_test))
20+
suite.addTests(loader.loadTestsFromModule(validate_test))
21+
suite.addTests(loader.loadTestsFromModule(retention_test))
2222
suite.addTests(loader.loadTestsFromModule(ptrack))
23-
# suite.addTests(loader.loadTestsFromModule(ptrack_clean))
24-
# suite.addTests(loader.loadTestsFromModule(ptrack_cluster))
25-
# suite.addTests(loader.loadTestsFromModule(ptrack_move_to_tablespace))
26-
# suite.addTests(loader.loadTestsFromModule(ptrack_recovery))
27-
# suite.addTests(loader.loadTestsFromModule(ptrack_vacuum))
28-
# suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_bits_frozen))
29-
# suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_bits_visibility))
30-
# suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_full))
31-
# suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_truncate))
32-
# suite.addTests(loader.loadTestsFromModule(replica))
33-
# suite.addTests(loader.loadTestsFromModule(pgpro560))
34-
# suite.addTests(loader.loadTestsFromModule(pgpro589))
35-
# suite.addTests(loader.loadTestsFromModule(false_positive))
36-
# suite.addTests(loader.loadTestsFromModule(compression))
37-
# suite.addTests(loader.loadTestsFromModule(page))
38-
# suite.addTests(loader.loadTestsFromModule(archive))
23+
suite.addTests(loader.loadTestsFromModule(ptrack_clean))
24+
suite.addTests(loader.loadTestsFromModule(ptrack_cluster))
25+
suite.addTests(loader.loadTestsFromModule(ptrack_move_to_tablespace))
26+
suite.addTests(loader.loadTestsFromModule(ptrack_recovery))
27+
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum))
28+
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_bits_frozen))
29+
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_bits_visibility))
30+
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_full))
31+
suite.addTests(loader.loadTestsFromModule(ptrack_vacuum_truncate))
32+
suite.addTests(loader.loadTestsFromModule(replica))
33+
suite.addTests(loader.loadTestsFromModule(pgpro560))
34+
suite.addTests(loader.loadTestsFromModule(pgpro589))
35+
suite.addTests(loader.loadTestsFromModule(false_positive))
36+
suite.addTests(loader.loadTestsFromModule(compression))
37+
suite.addTests(loader.loadTestsFromModule(page))
38+
suite.addTests(loader.loadTestsFromModule(archive))
3939

4040
return suite
4141

@@ -50,5 +50,5 @@ def load_tests(loader, tests, pattern):
5050
# https://jira.postgrespro.ru/secure/attachment/20420/20420_doc_logging.md
5151
# ptrack:
5252
# ptrack backup on replica should work correctly
53-
#
54-
# function to compare original instance and restored
53+
# archive:
54+
# immediate recovery and full recovery

0 commit comments

Comments
 (0)