/* Make local copy */
jcr->RescheduleIncompleteJobs = jcr->job->RescheduleIncompleteJobs;
- if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
- return do_vbackup_init(jcr);
- }
- free_rstorage(jcr); /* we don't read so release */
-
if (!get_or_create_fileset_record(jcr)) {
+ Dmsg1(100, "JobId=%d no FileSet\n", (int)jcr->JobId);
return false;
}
/*
* Get definitive Job level and since time
+ * unless it's a virtual full. In that case
+ * it is not needed.
*/
- get_level_since_time(jcr, jcr->since, sizeof(jcr->since));
+ if (!jcr->is_JobLevel(L_VIRTUAL_FULL)) {
+ get_level_since_time(jcr, jcr->since, sizeof(jcr->since));
+ }
apply_pool_overrides(jcr);
jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
if (jcr->jr.PoolId == 0) {
+ Dmsg1(100, "JobId=%d no PoolId\n", (int)jcr->JobId);
+ Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
return false;
}
+ /*
+ * If we are a virtual full job or got upgraded to one
+ * then we divert at this point and call the virtual full
+ * backup init method
+ */
+ if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
+ return do_vbackup_init(jcr);
+ }
+
+ free_rstorage(jcr); /* we don't read so release */
+
/* If pool storage specified, use it instead of job storage */
copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
utime_t MaxRunSchedTime; /* max run time in seconds from Scheduled time*/
utime_t RescheduleInterval; /* Reschedule interval */
utime_t MaxFullInterval; /* Maximum time interval between Fulls */
+ utime_t MaxVirtualFullInterval; /* Maximum time interval between Virtual Fulls */
utime_t MaxDiffInterval; /* Maximum time interval between Diffs */
utime_t DuplicateJobProximity; /* Permitted time between duplicicates */
utime_t SnapRetention; /* Snapshot retention period in seconds */
POOL *pool; /* Where is media -- Media Pool */
POOL *next_pool; /* Next Pool for Copy/Migrate/VirtualFull */
POOL *full_pool; /* Pool for Full backups */
+ POOL *vfull_pool; /* Pool for Virtual Full backups */
POOL *inc_pool; /* Pool for Incremental backups */
POOL *diff_pool; /* Pool for Differental backups */
char *selection_pattern;
POOL *pool; /* Pool override */
POOL *next_pool; /* Next pool override */
POOL *full_pool; /* Pool override */
+ POOL *vfull_pool; /* Pool override */
POOL *inc_pool; /* Pool override */
POOL *diff_pool; /* Pool override */
STORE *storage; /* Storage override */
int JobLevel;
bool have_full;
bool do_full = false;
+ bool do_vfull = false;
bool do_diff = false;
utime_t now;
utime_t last_full_time = 0;
do_diff = ((now - last_diff_time) >= jcr->job->MaxDiffInterval);
Dmsg2(50, "do_diff=%d diffInter=%lld\n", do_diff, jcr->job->MaxDiffInterval);
}
- /* Note, do_full takes precedence over do_diff */
+ /* Note, do_full takes precedence over do_vfull and do_diff */
if (have_full && jcr->job->MaxFullInterval > 0) {
do_full = ((now - last_full_time) >= jcr->job->MaxFullInterval);
}
+ else
+ if (have_full && jcr->job->MaxVirtualFullInterval > 0) {
+ do_vfull = ((now - last_full_time) >= jcr->job->MaxVirtualFullInterval);
+ }
+
free_pool_memory(stime);
if (do_full) {
bsnprintf(since, since_len, _(" (upgraded from %s)"),
level_to_str(jcr->getJobLevel()));
jcr->setJobLevel(jcr->jr.JobLevel = L_FULL);
- } else if (do_diff) {
+ } else if (do_vfull) {
+ /* No recent Full job found, and MaxVirtualFull is set so upgrade this one to Virtual Full */
+ Jmsg(jcr, M_INFO, 0, "%s", db_strerror(jcr->db));
+ Jmsg(jcr, M_INFO, 0, _("No prior or suitable Full backup found in catalog. Doing Virtual FULL backup.\n"));
+ bsnprintf(since, since_len, _(" (upgraded from %s)"),
+ level_to_str(jcr->getJobLevel()));
+ jcr->setJobLevel(jcr->jr.JobLevel = L_VIRTUAL_FULL);
+ } else if (do_diff) {
/* No recent diff job found, so upgrade this one to Diff */
Jmsg(jcr, M_INFO, 0, _("No prior or suitable Differential backup found in catalog. Doing Differential backup.\n"));
bsnprintf(since, since_len, _(" (upgraded from %s)"),
}
}
break;
+ case L_VIRTUAL_FULL:
+ if (jcr->vfull_pool) {
+ jcr->pool = jcr->vfull_pool;
+ pool_override = true;
+ if (jcr->run_vfull_pool_override) {
+ pm_strcpy(jcr->pool_source, _("Run VFullPool override"));
+ } else {
+ pm_strcpy(jcr->pool_source, _("Job VFullPool override"));
+ }
+ }
+ break;
case L_INCREMENTAL:
if (jcr->inc_pool) {
jcr->pool = jcr->inc_pool;
pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
}
jcr->full_pool = job->full_pool;
+ jcr->vfull_pool = job->vfull_pool;
jcr->inc_pool = job->inc_pool;
jcr->diff_pool = job->diff_pool;
if (job->pool->catalog) {
njcr->next_pool = jcr->next_pool;
njcr->run_next_pool_override = jcr->run_next_pool_override;
njcr->full_pool = jcr->full_pool;
+ njcr->vfull_pool = jcr->vfull_pool;
njcr->run_full_pool_override = jcr->run_full_pool_override;
+ njcr->run_vfull_pool_override = jcr->run_vfull_pool_override;
njcr->inc_pool = jcr->inc_pool;
njcr->run_inc_pool_override = jcr->run_inc_pool_override;
njcr->diff_pool = jcr->diff_pool;
case 'P': /* Pool */
case 'N': /* NextPool */
case 'f': /* FullPool */
+ case 'v': /* VFullPool */
case 'i': /* IncPool */
case 'd': /* DifPool */
token = lex_get_token(lc, T_NAME);
case 'f':
lrun.full_pool = (POOL *)res;
break;
+ case 'v':
+ lrun.vfull_pool = (POOL *)res;
+ break;
case 'i':
lrun.inc_pool = (POOL *)res;
break;
jcr->full_pool = run->full_pool; /* override full pool */
jcr->run_full_pool_override = true;
}
+ if (run->vfull_pool) {
+ jcr->vfull_pool = run->vfull_pool; /* override virtual full pool */
+ jcr->run_vfull_pool_override = true;
+ }
if (run->inc_pool) {
jcr->inc_pool = run->inc_pool; /* override inc pool */
jcr->run_inc_pool_override = true;
bool do_vbackup_init(JCR *jcr)
{
- if (!get_or_create_fileset_record(jcr)) {
- Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
- return false;
- }
-
- apply_pool_overrides(jcr);
-
- if (!allow_duplicate_job(jcr)) {
- return false;
- }
+ /*
+ * if the read pool has not been allocated yet due to the job
+ * being upgraded to a virtual full then allocate it now
+ */
+ if (!jcr->rpool_source)
+ jcr->rpool_source = get_pool_memory(PM_MESSAGE);
- jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
- if (jcr->jr.PoolId == 0) {
- Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
- Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
- return false;
- }
/*
* Note, at this point, pool is the pool for this job. We
* transfer it to rpool (read pool), and a bit later,
jcr->rpool = jcr->pool; /* save read pool */
pm_strcpy(jcr->rpool_source, jcr->pool_source);
- /* If pool storage specified, use it for restore */
+ /* If pool storage specified, use it for virtual full */
copy_rstorage(jcr, jcr->pool->storage, _("Pool resource"));
Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
POOL *next_pool; /* Next pool override */
POOL *rpool; /* Read pool. Used only in migration */
POOL *full_pool; /* Full backup pool resource */
+ POOL *vfull_pool; /* Virtual Full backup pool resource */
POOL *inc_pool; /* Incremental backup pool resource */
POOL *diff_pool; /* Differential backup pool resource */
FILESET *fileset; /* FileSet resource */
bool cmdline_next_pool_override; /* Next pool is overridden */
bool run_next_pool_override; /* Next pool is overridden */
bool run_full_pool_override;
+ bool run_vfull_pool_override;
bool run_inc_pool_override;
bool run_diff_pool_override;
bool sd_canceled; /* set if SD canceled */