The main author of Bacula is Kern Sibbald, with contributions from
many others, a complete list can be found in the file AUTHORS.
This program is Free Software; you can redistribute it and/or
- modify it under the terms of version two of the GNU General Public
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation and included
in the file LICENSE.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
DBId_t FileSetId; /* Id of FileSet */
};
-/* row: Job.Name, FileSet, Client.Name, FileSetId, ClientId */
+/* row: Job.Name, FileSet, Client.Name, FileSetId, ClientId, Type */
static int job_select_handler(void *ctx, int num_fields, char **row)
{
alist *lst = (alist *)ctx;
struct accurate_check_ctx *res;
-
- if (num_fields != 6) {
- return 1;
- }
+ ASSERT(num_fields == 6);
/* If this job doesn't exist anymore in the configuration, delete it */
if (GetResWithName(R_JOB, row[0]) == NULL) {
- return 1;
+ return 0;
}
/* If this fileset doesn't exist anymore in the configuration, delete it */
if (GetResWithName(R_FILESET, row[1]) == NULL) {
- return 1;
+ return 0;
}
/* If this client doesn't exist anymore in the configuration, delete it */
if (GetResWithName(R_CLIENT, row[2]) == NULL) {
- return 1;
+ return 0;
}
/* Don't compute accurate things for Verify jobs */
if (*row[5] == 'V') {
- return 1;
+ return 0;
}
res = (struct accurate_check_ctx*) malloc(sizeof(struct accurate_check_ctx));
char ed1[50], ed2[50];
alist *jobids_check=NULL;
struct accurate_check_ctx *elt;
- db_list_ctx jobids;
+ db_list_ctx jobids, tempids;
JOB_DBR jr;
db_lock(ua->db);
+ memset(&del, 0, sizeof(del));
memset(&cr, 0, sizeof(cr));
bstrncpy(cr.Name, client->name(), sizeof(cr.Name));
edit_int64(now - period, ed1); /* Jobs older than ed1 are good candidates */
edit_int64(cr.ClientId, ed2);
- memset(&del, 0, sizeof(del));
del.max_ids = 100;
del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
del.PurgedFiles = (char *)malloc(del.max_ids);
/*
* Select all files that are older than the JobRetention period
- * and stuff them into the "DeletionCandidates" table.
+ * and add them into the "DeletionCandidates" table.
*/
Mmsg(query,
"INSERT INTO DelCandidates "
"SELECT JobId,PurgedFiles,FileSetId,JobFiles,JobStatus "
"FROM Job "
- "WHERE Type IN ('B', 'C', 'M', 'V', 'D', 'R', 'c', 'm') "
+ "WHERE Type IN ('B', 'C', 'M', 'V', 'D', 'R', 'c', 'm', 'g') "
"AND JobTDate<%s AND ClientId=%s",
ed1, ed2);
"JOIN Job USING (JobId) "
"JOIN Client USING (ClientId) "
"JOIN FileSet ON (Job.FileSetId = FileSet.FileSetId) "
- "WHERE Type NOT IN ('D', 'R', 'c', 'm') " /* Discard Admin, Restore, Copy, Migration */
+ "WHERE Job.Type IN ('B') " /* Look only Backup jobs */
+ "AND Job.JobStatus IN ('T', 'W') " /* Look only useful jobs */
);
- /* The job_select_handler will skip jobs or fileset that are no longer
- * in the configuration file
+ /* The job_select_handler will skip jobs or filesets that are no longer
+ * in the configuration file. Interesting ClientId/FileSetId will be
+ * added to jobids_check
*/
if (!db_sql_query(ua->db, query.c_str(), job_select_handler, jobids_check)) {
ua->error_msg("%s", db_strerror(ua->db));
}
- /* For all jobs of this client, we exclude current jobs used for restore or
+ /* For this selection, we exclude current jobs used for restore or
* accurate. This will prevent to prune the last full backup used for
* current backup & restore
*/
/* To find useful jobs, we do like an incremental */
jr.JobLevel = L_INCREMENTAL;
foreach_alist(elt, jobids_check) {
- jr.ClientId = elt->ClientId;
+ jr.ClientId = elt->ClientId; /* should be always the same */
jr.FileSetId = elt->FileSetId;
- db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids);
+ db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids);
+ jobids.cat(tempids);
}
- /* Discard latest Verify level=InitCatalog job */
+ /* Discard latest Verify level=InitCatalog job
+ * TODO: can have multiple fileset
+ */
Mmsg(query,
"SELECT JobId, JobTDate "
"FROM Job "
/* We also need to exclude all basejobs used */
db_get_used_base_jobids(ua->jcr, ua->db, jobids.list, &jobids);
- /* Removing exceptions from the DelCandidates list */
- Mmsg(query, "DELETE FROM DelCandidates WHERE JobId IN (%s)", jobids.list);
+ /* Removing useful jobs from the DelCandidates list */
+ Mmsg(query, "DELETE FROM DelCandidates "
+ "WHERE JobId IN (%s) " /* JobId used in accurate */
+ "AND JobFiles!=0", /* Discard when JobFiles=0 */
+ jobids.list);
+
if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
ua->error_msg("%s", db_strerror(ua->db));
goto bail_out; /* Don't continue if the list isn't clean */
Dmsg1(60, "jobids to exclude = %s\n", jobids.list);
}
- /* Prune garbage jobs (JobStatus not successful) */
- Mmsg(query,
- "INSERT INTO DelCandidates "
- "SELECT JobId,PurgedFiles,FileSetId,JobFiles,JobStatus "
- "FROM Job "
- "WHERE ( JobFiles=0 "
- "OR JobStatus NOT IN ('T', 'W') "
- ") "
- "AND JobTDate < %s "
- "AND ClientId = %s ",
- ed1, ed2);
-
- Dmsg1(150, "Query=%s\n", query.c_str());
- if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) {
- ua->error_msg("%s", db_strerror(ua->db));
- }
-
/* We use DISTINCT because we can have two times the same job */
Mmsg(query,
"SELECT DISTINCT DelCandidates.JobId,DelCandidates.PurgedFiles "