Skip to content

Commit a425a96

Browse files
committed
Merge branch 'issue_120'
2 parents 703d311 + aa56f1d commit a425a96

File tree

10 files changed

+275
-31
lines changed

10 files changed

+275
-31
lines changed

doc/pgprobackup.xml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3257,6 +3257,17 @@ pg_probackup delete -B <replaceable>backup_dir</replaceable> --instance <replace
32573257
all the available backups according to the current retention
32583258
policy, without performing any irreversible actions.
32593259
</para>
3260+
<para>
3261+
To delete all backups with specific status, use the <option>--status</option>:
3262+
</para>
3263+
<programlisting>
3264+
pg_probackup delete -B <replaceable>backup_dir</replaceable> --instance <replaceable>instance_name</replaceable> --status=ERROR
3265+
</programlisting>
3266+
3267+
<para>
3268+
Deleting backups by status ignores established retention policies.
3269+
</para>
3270+
32603271
</refsect2>
32613272
</refsect1>
32623273

@@ -3935,10 +3946,9 @@ pg_probackup merge -B <replaceable>backup_dir</replaceable> --instance <replacea
39353946
<programlisting>
39363947
pg_probackup delete -B <replaceable>backup_dir</replaceable> --instance <replaceable>instance_name</replaceable>
39373948
[--help] [-j <replaceable>num_threads</replaceable>] [--progress]
3938-
[--retention-redundancy=<replaceable>redundancy</replaceable>][--retention-window=<replaceable>window</replaceable>][--wal-depth=<replaceable>wal_depth</replaceable>]
3939-
[--delete-wal] {-i <replaceable>backup_id</replaceable> | --delete-expired [--merge-expired] | --merge-expired}
3940-
[--dry-run]
3941-
[<replaceable>logging_options</replaceable>]
3949+
[--retention-redundancy=<replaceable>redundancy</replaceable>][--retention-window=<replaceable>window</replaceable>][--wal-depth=<replaceable>wal_depth</replaceable>] [--delete-wal]
3950+
{-i <replaceable>backup_id</replaceable> | --delete-expired [--merge-expired] | --merge-expired | --status=backup_status}
3951+
[--dry-run] [<replaceable>logging_options</replaceable>]
39423952
</programlisting>
39433953
<para>
39443954
Deletes backup with specified <replaceable>backup_id</replaceable>

src/catalog.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2447,3 +2447,23 @@ get_backup_index_number(parray *backup_list, pgBackup *backup)
24472447
elog(WARNING, "Failed to find backup %s", base36enc(backup->start_time));
24482448
return -1;
24492449
}
2450+
2451+
/* On backup_list lookup children of target_backup and append them to append_list */
2452+
void
2453+
append_children(parray *backup_list, pgBackup *target_backup, parray *append_list)
2454+
{
2455+
int i;
2456+
2457+
for (i = 0; i < parray_num(backup_list); i++)
2458+
{
2459+
pgBackup *backup = (pgBackup *) parray_get(backup_list, i);
2460+
2461+
/* check if backup is descendant of target backup */
2462+
if (is_parent(target_backup->start_time, backup, false))
2463+
{
2464+
/* if backup is already in the list, then skip it */
2465+
if (!parray_contains(append_list, backup))
2466+
parray_append(append_list, backup);
2467+
}
2468+
}
2469+
}

src/delete.c

Lines changed: 106 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ do_delete(time_t backup_id)
123123
* which FULL backup should be keeped for redundancy obligation(only valid do),
124124
* but if invalid backup is not guarded by retention - it is removed
125125
*/
126-
int do_retention(void)
126+
void do_retention(void)
127127
{
128128
parray *backup_list = NULL;
129129
parray *to_keep_list = parray_new();
@@ -154,7 +154,7 @@ int do_retention(void)
154154
/* Retention is disabled but we still can cleanup wal */
155155
elog(WARNING, "Retention policy is not set");
156156
if (!delete_wal)
157-
return 0;
157+
return;
158158
}
159159
else
160160
/* At least one retention policy is active */
@@ -196,9 +196,6 @@ int do_retention(void)
196196
parray_free(backup_list);
197197
parray_free(to_keep_list);
198198
parray_free(to_purge_list);
199-
200-
return 0;
201-
202199
}
203200

204201
/* Evaluate every backup by retention policies and populate purge and keep lists.
@@ -1023,3 +1020,107 @@ do_delete_instance(void)
10231020
elog(INFO, "Instance '%s' successfully deleted", instance_name);
10241021
return 0;
10251022
}
1023+
1024+
/* Delete all backups of given status in instance */
1025+
void
1026+
do_delete_status(InstanceConfig *instance_config, const char *status)
1027+
{
1028+
int i;
1029+
parray *backup_list, *delete_list;
1030+
const char *pretty_status;
1031+
int n_deleted = 0, n_found = 0;
1032+
size_t size_to_delete = 0;
1033+
char size_to_delete_pretty[20];
1034+
pgBackup *backup;
1035+
1036+
BackupStatus status_for_delete = str2status(status);
1037+
delete_list = parray_new();
1038+
1039+
if (status_for_delete == BACKUP_STATUS_INVALID)
1040+
elog(ERROR, "Unknown value for '--status' option: '%s'", status);
1041+
1042+
/*
1043+
* User may have provided status string in lower case, but
1044+
* we should print backup statuses consistently with show command,
1045+
* so convert it.
1046+
*/
1047+
pretty_status = status2str(status_for_delete);
1048+
1049+
backup_list = catalog_get_backup_list(instance_config->name, INVALID_BACKUP_ID);
1050+
1051+
if (parray_num(backup_list) == 0)
1052+
{
1053+
elog(WARNING, "Instance '%s' has no backups", instance_config->name);
1054+
return;
1055+
}
1056+
1057+
if (dry_run)
1058+
elog(INFO, "Deleting all backups with status '%s' in dry run mode", pretty_status);
1059+
else
1060+
elog(INFO, "Deleting all backups with status '%s'", pretty_status);
1061+
1062+
/* Selects backups with specified status and their children into delete_list array. */
1063+
for (i = 0; i < parray_num(backup_list); i++)
1064+
{
1065+
backup = (pgBackup *) parray_get(backup_list, i);
1066+
1067+
if (backup->status == status_for_delete)
1068+
{
1069+
n_found++;
1070+
1071+
/* incremental backup can be already in delete_list due to append_children() */
1072+
if (parray_contains(delete_list, backup))
1073+
continue;
1074+
parray_append(delete_list, backup);
1075+
1076+
append_children(backup_list, backup, delete_list);
1077+
}
1078+
}
1079+
1080+
parray_qsort(delete_list, pgBackupCompareIdDesc);
1081+
1082+
/* delete and calculate free size from delete_list */
1083+
for (i = 0; i < parray_num(delete_list); i++)
1084+
{
1085+
backup = (pgBackup *)parray_get(delete_list, i);
1086+
1087+
elog(INFO, "Backup %s with status %s %s be deleted",
1088+
base36enc(backup->start_time), status2str(backup->status), dry_run ? "can" : "will");
1089+
1090+
size_to_delete += backup->data_bytes;
1091+
if (backup->stream)
1092+
size_to_delete += backup->wal_bytes;
1093+
1094+
if (!dry_run && lock_backup(backup))
1095+
delete_backup_files(backup);
1096+
1097+
n_deleted++;
1098+
}
1099+
1100+
/* Inform about data size to free */
1101+
if (size_to_delete >= 0)
1102+
{
1103+
pretty_size(size_to_delete, size_to_delete_pretty, lengthof(size_to_delete_pretty));
1104+
elog(INFO, "Resident data size to free by delete of %i backups: %s",
1105+
n_deleted, size_to_delete_pretty);
1106+
}
1107+
1108+
/* delete selected backups */
1109+
if (!dry_run && n_deleted > 0)
1110+
elog(INFO, "Successfully deleted %i %s from instance '%s'",
1111+
n_deleted, n_deleted == 1 ? "backup" : "backups",
1112+
instance_config->name);
1113+
1114+
1115+
if (n_found == 0)
1116+
elog(WARNING, "Instance '%s' has no backups with status '%s'",
1117+
instance_config->name, pretty_status);
1118+
1119+
// we don`t do WAL purge here, because it is impossible to correctly handle
1120+
// dry-run case.
1121+
1122+
/* Cleanup */
1123+
parray_free(delete_list);
1124+
parray_walk(backup_list, pgBackupFree);
1125+
parray_free(backup_list);
1126+
}

src/help.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,8 @@ help_pg_probackup(void)
193193
printf(_(" [--retention-redundancy=retention-redundancy]\n"));
194194
printf(_(" [--retention-window=retention-window]\n"));
195195
printf(_(" [--wal-depth=wal-depth]\n"));
196-
printf(_(" [--delete-wal] [-i backup-id | --delete-expired | --merge-expired]\n"));
196+
printf(_(" [-i backup-id | --delete-expired | --merge-expired | --status=backup_status]\n"));
197+
printf(_(" [--delete-wal]\n"));
197198
printf(_(" [--dry-run]\n"));
198199
printf(_(" [--help]\n"));
199200

@@ -638,6 +639,7 @@ help_delete(void)
638639
printf(_(" --wal-depth=wal-depth number of latest valid backups per timeline that must\n"));
639640
printf(_(" retain the ability to perform PITR; 0 disables; (default: 0)\n"));
640641
printf(_(" --dry-run perform a trial run without any changes\n"));
642+
printf(_(" --status=backup_status delete all backups with specified status\n"));
641643

642644
printf(_("\n Logging options:\n"));
643645
printf(_(" --log-level-console=log-level-console\n"));

src/pg_probackup.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ bool delete_expired = false;
117117
bool merge_expired = false;
118118
bool force = false;
119119
bool dry_run = false;
120-
120+
static char *delete_status = NULL;
121121
/* compression options */
122122
bool compress_shortcut = false;
123123

@@ -209,6 +209,8 @@ static ConfigOption cmd_options[] =
209209
/* delete options */
210210
{ 'b', 145, "wal", &delete_wal, SOURCE_CMD_STRICT },
211211
{ 'b', 146, "expired", &delete_expired, SOURCE_CMD_STRICT },
212+
{ 's', 172, "status", &delete_status, SOURCE_CMD_STRICT },
213+
212214
/* TODO not implemented yet */
213215
{ 'b', 147, "force", &force, SOURCE_CMD_STRICT },
214216
/* compression options */
@@ -821,13 +823,20 @@ main(int argc, char *argv[])
821823
elog(ERROR, "You cannot specify --delete-expired and (-i, --backup-id) options together");
822824
if (merge_expired && backup_id_string)
823825
elog(ERROR, "You cannot specify --merge-expired and (-i, --backup-id) options together");
824-
if (!delete_expired && !merge_expired && !delete_wal && !backup_id_string)
826+
if (delete_status && backup_id_string)
827+
elog(ERROR, "You cannot specify --status and (-i, --backup-id) options together");
828+
if (!delete_expired && !merge_expired && !delete_wal && delete_status == NULL && !backup_id_string)
825829
elog(ERROR, "You must specify at least one of the delete options: "
826-
"--delete-expired |--delete-wal |--merge-expired |(-i, --backup-id)");
830+
"--delete-expired |--delete-wal |--merge-expired |--status |(-i, --backup-id)");
827831
if (!backup_id_string)
828-
return do_retention();
832+
{
833+
if (delete_status)
834+
do_delete_status(&instance_config, delete_status);
835+
else
836+
do_retention();
837+
}
829838
else
830-
do_delete(current.backup_id);
839+
do_delete(current.backup_id);
831840
break;
832841
case MERGE_CMD:
833842
do_merge(current.backup_id);

src/pg_probackup.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -722,8 +722,9 @@ extern int do_show(const char *instance_name, time_t requested_backup_id, bool s
722722
/* in delete.c */
723723
extern void do_delete(time_t backup_id);
724724
extern void delete_backup_files(pgBackup *backup);
725-
extern int do_retention(void);
725+
extern void do_retention(void);
726726
extern int do_delete_instance(void);
727+
extern void do_delete_status(InstanceConfig *instance_config, const char *status);
727728

728729
/* in fetch.c */
729730
extern char *slurpFile(const char *datadir,
@@ -807,8 +808,8 @@ extern int scan_parent_chain(pgBackup *current_backup, pgBackup **result_backup)
807808

808809
extern bool is_parent(time_t parent_backup_time, pgBackup *child_backup, bool inclusive);
809810
extern bool is_prolific(parray *backup_list, pgBackup *target_backup);
810-
extern bool in_backup_list(parray *backup_list, pgBackup *target_backup);
811811
extern int get_backup_index_number(parray *backup_list, pgBackup *backup);
812+
extern void append_children(parray *backup_list, pgBackup *target_backup, parray *append_list);
812813
extern bool launch_agent(void);
813814
extern void launch_ssh(char* argv[]);
814815
extern void wait_ssh(void);
@@ -953,6 +954,7 @@ extern void copy_pgcontrol_file(const char *from_fullpath, fio_location from_loc
953954

954955
extern void time2iso(char *buf, size_t len, time_t time);
955956
extern const char *status2str(BackupStatus status);
957+
extern BackupStatus str2status(const char *status);
956958
extern const char *base36enc(long unsigned int value);
957959
extern char *base36enc_dup(long unsigned int value);
958960
extern long unsigned int base36dec(const char *text);

src/util.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,21 @@
1818

1919
#include <sys/stat.h>
2020

21+
static const char *statusName[] =
22+
{
23+
"UNKNOWN",
24+
"OK",
25+
"ERROR",
26+
"RUNNING",
27+
"MERGING",
28+
"MERGED",
29+
"DELETING",
30+
"DELETED",
31+
"DONE",
32+
"ORPHAN",
33+
"CORRUPT"
34+
};
35+
2136
const char *
2237
base36enc(long unsigned int value)
2338
{
@@ -462,22 +477,21 @@ parse_program_version(const char *program_version)
462477
const char *
463478
status2str(BackupStatus status)
464479
{
465-
static const char *statusName[] =
466-
{
467-
"UNKNOWN",
468-
"OK",
469-
"ERROR",
470-
"RUNNING",
471-
"MERGING",
472-
"MERGED",
473-
"DELETING",
474-
"DELETED",
475-
"DONE",
476-
"ORPHAN",
477-
"CORRUPT"
478-
};
479480
if (status < BACKUP_STATUS_INVALID || BACKUP_STATUS_CORRUPT < status)
480481
return "UNKNOWN";
481482

482483
return statusName[status];
483484
}
485+
486+
BackupStatus
487+
str2status(const char *status)
488+
{
489+
BackupStatus i;
490+
491+
for (i = BACKUP_STATUS_INVALID; i <= BACKUP_STATUS_CORRUPT; i++)
492+
{
493+
if (pg_strcasecmp(status, statusName[i]) == 0) return i;
494+
}
495+
496+
return BACKUP_STATUS_INVALID;
497+
}

src/utils/parray.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,16 @@ parray_bsearch(parray *array, const void *key, int(*compare)(const void *, const
197197
{
198198
return bsearch(&key, array->data, array->used, sizeof(void *), compare);
199199
}
200+
201+
/* checks that parray contains element */
202+
bool parray_contains(parray *array, void *elem)
203+
{
204+
int i;
205+
206+
for (i = 0; i < parray_num(array); i++)
207+
{
208+
if (parray_get(array, i) == elem)
209+
return true;
210+
}
211+
return false;
212+
}

src/utils/parray.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ extern size_t parray_num(const parray *array);
3030
extern void parray_qsort(parray *array, int(*compare)(const void *, const void *));
3131
extern void *parray_bsearch(parray *array, const void *key, int(*compare)(const void *, const void *));
3232
extern void parray_walk(parray *array, void (*action)(void *));
33+
extern bool parray_contains(parray *array, void *elem);
3334

3435
#endif /* PARRAY_H */
3536

0 commit comments

Comments
 (0)