]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/ua_prune.c
Try to fix #1660 about segfault during pruning
[bacula/bacula] / bacula / src / dird / ua_prune.c
index 30366b24071a5bab71e4973cf037367945e99a3a..fb2efb09a4b8d277fac0aa766e9af64cbf10735b 100644 (file)
@@ -6,7 +6,7 @@
    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.
 
@@ -15,7 +15,7 @@
    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.
@@ -348,34 +348,31 @@ struct accurate_check_ctx {
    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));
@@ -408,10 +405,11 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
    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));
@@ -441,20 +439,19 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
    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);
 
@@ -477,17 +474,19 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
        "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
     */
@@ -495,12 +494,15 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
    /* 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 "
@@ -521,8 +523,12 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
       /* 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 */
@@ -530,23 +536,6 @@ int prune_jobs(UAContext *ua, CLIENT *client, POOL *pool, int JobType)
       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 "