NULL};
ua->warning_msg(_(
- "\nThis command is can be DANGEROUS!!!\n\n"
+ "\nThis command can be DANGEROUS!!!\n\n"
"It purges (deletes) all Files from a Job,\n"
"JobId, Client or Volume; or it purges (deletes)\n"
"all Jobs from a Client or Volume without regard\n"
- "for retention periods. Normally you should use the\n"
+ "to retention periods. Normally you should use the\n"
"PRUNE command, which respects retention periods.\n"));
if (!open_db(ua)) {
case 1: /* Volume */
if (select_media_dbr(ua, &mr)) {
purge_jobs_from_volume(ua, &mr, /*force*/true);
-
-purge_jobs_from_volume(ua, &mr);
}
return 1;
}
db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
Dmsg1(050, "Delete File sql=%s\n", query.c_str());
+ Mmsg(query, "DELETE FROM BaseFiles WHERE JobId IN (%s)", jobs);
+ db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+ Dmsg1(050, "Delete BaseFiles sql=%s\n", query.c_str());
+
/*
* Now mark Job as having files purged. This is necessary to
* avoid having too many Jobs to process in future prunings. If
}
}
+/*
+ * Change the type of the next copy job to backup.
+ * We need to upgrade the next copy of a normal job,
+ * and also upgrade the next copy when the normal job
+ * already have been purged.
+ *
+ * JobId: 1 PriorJobId: 0 (original)
+ * JobId: 2 PriorJobId: 1 (first copy)
+ * JobId: 3 PriorJobId: 1 (second copy)
+ *
+ * JobId: 2 PriorJobId: 1 (first copy, now regular backup)
+ * JobId: 3 PriorJobId: 1 (second copy)
+ *
+ * => Search through PriorJobId in jobid and
+ * PriorJobId in PriorJobId (jobid)
+ */
+void upgrade_copies(UAContext *ua, char *jobs)
+{
+ POOL_MEM query(PM_MESSAGE);
+
+ db_lock(ua->db);
+ /* Do it in two times for mysql */
+ Mmsg(query, "CREATE TEMPORARY TABLE cpy_tmp AS "
+ "SELECT MIN(JobId) AS JobId FROM Job " /* Choose the oldest job */
+ "WHERE Type='%c' "
+ "AND ( PriorJobId IN (%s) "
+ "OR "
+ " PriorJobId IN ( "
+ "SELECT PriorJobId "
+ "FROM Job "
+ "WHERE JobId IN (%s) "
+ " AND Type='B' "
+ ") "
+ ") "
+ "GROUP BY PriorJobId ", /* one result per copy */
+ JT_JOB_COPY, jobs, jobs);
+ db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+ Dmsg1(050, "Upgrade copies Log sql=%s\n", query.c_str());
+
+ /* Now upgrade first copy to Backup */
+ Mmsg(query, "UPDATE Job SET Type='B' " /* JT_JOB_COPY => JT_BACKUP */
+ "WHERE JobId IN ( SELECT JobId FROM cpy_tmp )");
+
+ db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
+ Mmsg(query, "DROP TABLE cpy_tmp");
+ db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
+ db_unlock(ua->db);
+}
+
/*
* Remove all records from catalog for a list of JobIds
*/
db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
Dmsg1(050, "Delete Log sql=%s\n", query.c_str());
+ upgrade_copies(ua, jobs);
+
/* Now remove the Job record itself */
Mmsg(query, "DELETE FROM Job WHERE JobId IN (%s)", jobs);
db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
Dmsg1(050, "Delete Job sql=%s\n", query.c_str());
}
-
void purge_files_from_volume(UAContext *ua, MEDIA_DBR *mr )
{} /* ***FIXME*** implement */
return purged;
}
+static BSOCK *open_sd_bsock(UAContext *ua)
+{
+ STORE *store = ua->jcr->wstore;
+
+ if (!ua->jcr->store_bsock) {
+ ua->send_msg(_("Connecting to Storage daemon %s at %s:%d ...\n"),
+ store->name(), store->address, store->SDport);
+ if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+ ua->error_msg(_("Failed to connect to Storage daemon.\n"));
+ return NULL;
+ }
+ }
+ return ua->jcr->store_bsock;
+}
+
/*
* IF volume status is Append, Full, Used, or Error, mark it Purged
* Purged volumes can then be recycled (if enabled).
*/
bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
{
+ char dev_name[MAX_NAME_LENGTH];
JCR *jcr = ua->jcr;
if (strcmp(mr->VolStatus, "Append") == 0 ||
strcmp(mr->VolStatus, "Full") == 0 ||
if (!db_update_media_record(jcr, ua->db, mr)) {
return false;
}
+
+ if (mr->ActionOnPurge > 0) {
+ /* Send the command to truncate the volume after purge. If this feature
+ * is disabled for the specific device, this will be a no-op.
+ */
+ BSOCK *sd;
+ if ((sd=open_sd_bsock(ua)) != NULL) {
+ bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
+ bash_spaces(dev_name);
+ bash_spaces(mr->VolumeName);
+ sd->fsend("action_on_purge %s vol=%s action=%d",
+ ua->jcr->wstore->dev_name(),
+ mr->VolumeName,
+ mr->ActionOnPurge);
+ unbash_spaces(mr->VolumeName);
+ while (sd->recv() >= 0) {
+ ua->send_msg("%s", sd->msg);
+ }
+
+ sd->signal(BNET_TERMINATE);
+ sd->close();
+ ua->jcr->store_bsock = NULL;
+ } else {
+ ua->error_msg(_("Could not connect to storage daemon"));
+ return false;
+ }
+ }
+
pm_strcpy(jcr->VolumeName, mr->VolumeName);
generate_job_event(jcr, "VolumePurged");
generate_plugin_event(jcr, bEventVolumePurged);