/* Modify the RecyclePool of a Volume */ void update_vol_recyclepool(UAContext *ua, char *val, MEDIA_DBR *mr) { POOL_DBR pr; POOL_MEM query(PM_MESSAGE); char ed1[50], ed2[50], *poolname; if(val && *val) { /* update volume recyclepool="Scratch" */ /* If a pool name is given, look up the PoolId */ memset(&pr, 0, sizeof(pr)); bstrncpy(pr.Name, val, sizeof(pr.Name)); if (!get_pool_dbr(ua, &pr, NT_("recyclepool"))) { return; } /* pool = select_pool_resource(ua); */ mr->RecyclePoolId = pr.PoolId; /* get the PoolId */ poolname = pr.Name; } else { /* update volume recyclepool="" */ /* If no pool name is given, set the PoolId to 0 (the default) */ mr->RecyclePoolId = 0; poolname = _("*None*"); } db_lock(ua->db); Mmsg(query, "UPDATE Media SET RecyclePoolId=%s WHERE MediaId=%s", edit_int64(mr->RecyclePoolId, ed1), edit_int64(mr->MediaId, ed2)); if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New RecyclePool is: %s\n"), poolname); } db_unlock(ua->db); }
static int send_volume_info_to_storage_daemon(JCR *jcr, BSOCK *sd, MEDIA_DBR *mr) { int status; char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50]; jcr->MediaId = mr->MediaId; pm_strcpy(jcr->VolumeName, mr->VolumeName); bash_spaces(mr->VolumeName); status = sd->fsend(OK_media, mr->VolumeName, mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), mr->VolMounts, mr->VolErrors, mr->VolWrites, edit_uint64(mr->MaxVolBytes, ed2), edit_uint64(mr->VolCapacityBytes, ed3), mr->VolStatus, mr->Slot, mr->MaxVolJobs, mr->MaxVolFiles, mr->InChanger, edit_int64(mr->VolReadTime, ed4), edit_int64(mr->VolWriteTime, ed5), mr->EndFile, mr->EndBlock, mr->LabelType, edit_uint64(mr->MediaId, ed6), mr->EncrKey, mr->MinBlocksize, mr->MaxBlocksize); unbash_spaces(mr->VolumeName); Dmsg2(100, "Vol Info for %s: %s", jcr->Job, sd->msg); return status; }
/* * This routine will purge (delete) all records * associated with a particular Volume. It will * not delete the media record itself. * TODO: This function is broken and it doesn't purge * File, BaseFiles, Log, ... * We call it from relabel and delete volume=, both ensure * that the volume is properly purged. */ static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr) { POOLMEM *query = get_pool_memory(PM_MESSAGE); struct s_del_ctx del; char ed1[50]; int i; del.num_ids = 0; del.tot_ids = 0; del.num_del = 0; del.max_ids = 0; Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId); del.max_ids = mr->VolJobs; if (del.max_ids < 100) { del.max_ids = 100; } else if (del.max_ids > MAX_DEL_LIST_LEN) { del.max_ids = MAX_DEL_LIST_LEN; } del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del); for (i=0; i < del.num_ids; i++) { Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]); Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1)); db_sql_query(mdb, query); Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1)); db_sql_query(mdb, query); Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1)); db_sql_query(mdb, query); } free(del.JobId); free_pool_memory(query); return 1; }
/* Modify the Pool in which this Volume is located */ void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr) { POOL_DBR pr; POOL_MEM query(PM_MESSAGE); char ed1[50], ed2[50]; memset(&pr, 0, sizeof(pr)); bstrncpy(pr.Name, val, sizeof(pr.Name)); if (!get_pool_dbr(ua, &pr)) { return; } mr->PoolId = pr.PoolId; /* set new PoolId */ /* */ db_lock(ua->db); Mmsg(query, "UPDATE Media SET PoolId=%s WHERE MediaId=%s", edit_int64(mr->PoolId, ed1), edit_int64(mr->MediaId, ed2)); if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New Pool is: %s\n"), pr.Name); opr->NumVols--; if (!db_update_pool_record(ua->jcr, ua->db, opr)) { ua->error_msg("%s", db_strerror(ua->db)); } pr.NumVols++; if (!db_update_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } db_unlock(ua->db); }
/* * Find last failed job since given start-time * it must be either Full or Diff. * * Returns: false on failure * true on success, jr is unchanged and stime unchanged * level returned in JobLevel */ bool BDB::bdb_find_failed_job_since(JCR *jcr, JOB_DBR *jr, POOLMEM *stime, int &JobLevel) { SQL_ROW row; char ed1[50], ed2[50]; char esc_name[MAX_ESCAPE_NAME_LENGTH]; bdb_lock(); bdb_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name)); /* Differential is since last Full backup */ Mmsg(cmd, "SELECT Level FROM Job WHERE JobStatus IN ('%c','%c', '%c', '%c') AND " "Type='%c' AND Level IN ('%c','%c') AND Name='%s' AND ClientId=%s " "AND FileSetId=%s AND StartTime>'%s' " "ORDER BY StartTime DESC LIMIT 1", JS_Canceled, JS_ErrorTerminated, JS_Error, JS_FatalError, jr->JobType, L_FULL, L_DIFFERENTIAL, esc_name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2), stime); if (!QueryDB(jcr, cmd)) { bdb_unlock(); return false; } if ((row = sql_fetch_row()) == NULL) { sql_free_result(); bdb_unlock(); return false; } JobLevel = (int)*row[0]; sql_free_result(); bdb_unlock(); return true; }
/* * If we have a non-zero InChanger, ensure that no other Media * record has InChanger set on the same Slot. * * This routine assumes the database is already locked. */ void db_make_inchanger_unique(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) { char ed1[50], ed2[50]; char esc[MAX_ESCAPE_NAME_LENGTH]; if (mr->InChanger != 0 && mr->Slot != 0 && mr->StorageId != 0) { if (mr->MediaId != 0) { Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE " "Slot=%d AND StorageId=%s AND MediaId!=%s", mr->Slot, edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2)); } else if (*mr->VolumeName) { mdb->db_escape_string(jcr, esc,mr->VolumeName,strlen(mr->VolumeName)); Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE " "Slot=%d AND StorageId=%s AND VolumeName!='%s'", mr->Slot, edit_int64(mr->StorageId, ed1), esc); } else { /* used by ua_label to reset all volume with this slot */ Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0, Slot=0 WHERE " "Slot=%d AND StorageId=%s", mr->Slot, edit_int64(mr->StorageId, ed1), mr->VolumeName); } Dmsg1(100, "%s\n", mdb->cmd); UPDATE_DB_NO_AFR(jcr, mdb, mdb->cmd); } }
bool db_update_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr) { bool retval; char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50]; char esc[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); mdb->db_escape_string(jcr, esc, pr->LabelFormat, strlen(pr->LabelFormat)); Mmsg(mdb->cmd, "SELECT count(*) from Media WHERE PoolId=%s", edit_int64(pr->PoolId, ed4)); pr->NumVols = get_sql_record_max(jcr, mdb); Dmsg1(400, "NumVols=%d\n", pr->NumVols); Mmsg(mdb->cmd, "UPDATE Pool SET NumVols=%u,MaxVols=%u,UseOnce=%d,UseCatalog=%d," "AcceptAnyVolume=%d,VolRetention='%s',VolUseDuration='%s'," "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,Recycle=%d," "AutoPrune=%d,LabelType=%d,LabelFormat='%s',RecyclePoolId=%s," "ScratchPoolId=%s,ActionOnPurge=%d WHERE PoolId=%s", pr->NumVols, pr->MaxVols, pr->UseOnce, pr->UseCatalog, pr->AcceptAnyVolume, edit_uint64(pr->VolRetention, ed1), edit_uint64(pr->VolUseDuration, ed2), pr->MaxVolJobs, pr->MaxVolFiles, edit_uint64(pr->MaxVolBytes, ed3), pr->Recycle, pr->AutoPrune, pr->LabelType, esc, edit_int64(pr->RecyclePoolId,ed5), edit_int64(pr->ScratchPoolId,ed6), pr->ActionOnPurge, ed4); retval = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); return retval; }
/* * Get prune list for a volume */ int get_prune_list_for_volume(UAContext *ua, MEDIA_DBR *mr, del_ctx *del) { POOL_MEM query(PM_MESSAGE); int count = 0; utime_t now, period; char ed1[50], ed2[50]; if (mr->Enabled == 2) { return 0; /* cannot prune Archived volumes */ } /* * Now add to the list of JobIds for Jobs written to this Volume */ edit_int64(mr->MediaId, ed1); period = mr->VolRetention; now = (utime_t)time(NULL); edit_int64(now-period, ed2); Mmsg(query, sel_JobMedia, ed1, ed2); Dmsg3(250, "Now=%d period=%d now-period=%s\n", (int)now, (int)period, ed2); Dmsg1(050, "Query=%s\n", query.c_str()); if (!db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)del)) { if (ua->verbose) { ua->error_msg("%s", db_strerror(ua->db)); } Dmsg0(050, "Count failed\n"); goto bail_out; } count = exclude_running_jobs_from_list(del); bail_out: return count; }
/* * Find last failed job since given start-time * it must be either Full or Diff. * * Returns: false on failure * true on success, jr is unchanged and stime unchanged * level returned in JobLevel */ bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel) { SQL_ROW row; char ed1[50], ed2[50]; db_lock(mdb); /* Differential is since last Full backup */ Mmsg(mdb->cmd, "SELECT Level FROM Job WHERE JobStatus!='T' AND Type='%c' AND " "Level IN ('%c','%c') AND Name='%s' AND ClientId=%s " "AND FileSetId=%s AND StartTime>'%s' " "ORDER BY StartTime DESC LIMIT 1", jr->JobType, L_FULL, L_DIFFERENTIAL, jr->Name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2), stime); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); return false; } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); db_unlock(mdb); return false; } JobLevel = (int)*row[0]; sql_free_result(mdb); db_unlock(mdb); return true; }
/* * Update the Job record at start of Job * * Returns: false on failure * true on success */ bool db_update_job_start_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { char dt[MAX_TIME_LENGTH]; time_t stime; struct tm tm; btime_t JobTDate; bool retval; char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50]; stime = jr->StartTime; (void)localtime_r(&stime, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm); JobTDate = (btime_t)stime; db_lock(mdb); Mmsg(mdb->cmd, "UPDATE Job SET JobStatus='%c',Level='%c',StartTime='%s'," "ClientId=%s,JobTDate=%s,PoolId=%s,FileSetId=%s WHERE JobId=%s", (char)(jcr->JobStatus), (char)(jr->JobLevel), dt, edit_int64(jr->ClientId, ed1), edit_uint64(JobTDate, ed2), edit_int64(jr->PoolId, ed3), edit_int64(jr->FileSetId, ed4), edit_int64(jr->JobId, ed5)); retval = UPDATE_DB(jcr, mdb, mdb->cmd); mdb->changes = 0; db_unlock(mdb); return retval; }
/* * Find last failed job since given start-time * it must be either Full or Diff. * * Returns: false on failure * true on success, jr is unchanged and stime unchanged * level returned in JobLevel */ bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel) { bool retval = false; SQL_ROW row; char ed1[50], ed2[50]; char esc_name[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); mdb->db_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name)); /* Differential is since last Full backup */ Mmsg(mdb->cmd, "SELECT Level FROM Job WHERE JobStatus NOT IN ('T','W') AND " "Type='%c' AND Level IN ('%c','%c') AND Name='%s' AND ClientId=%s " "AND FileSetId=%s AND StartTime>'%s' " "ORDER BY StartTime DESC LIMIT 1", jr->JobType, L_FULL, L_DIFFERENTIAL, esc_name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2), stime); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { goto bail_out; } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); goto bail_out; } JobLevel = (int)*row[0]; sql_free_result(mdb); retval = true; bail_out: db_unlock(mdb); return retval; }
/* * Find JobId of last job that ran. E.g. for * VERIFY_CATALOG we want the JobId of the last INIT. * For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the last Job. * * Returns: true on success * false on failure */ bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) { SQL_ROW row; char ed1[50]; /* Find last full */ db_lock(mdb); Dmsg2(100, "JobLevel=%d JobType=%d\n", jr->JobLevel, jr->JobType); if (jr->JobLevel == L_VERIFY_CATALOG) { Mmsg(mdb->cmd, "SELECT JobId FROM Job WHERE Type='V' AND Level='%c' AND " " JobStatus IN ('T','W') AND Name='%s' AND " "ClientId=%s ORDER BY StartTime DESC LIMIT 1", L_VERIFY_INIT, jr->Name, edit_int64(jr->ClientId, ed1)); } else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG || jr->JobLevel == L_VERIFY_DISK_TO_CATALOG || jr->JobType == JT_BACKUP) { if (Name) { Mmsg(mdb->cmd, "SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND " "Name='%s' ORDER BY StartTime DESC LIMIT 1", Name); } else { Mmsg(mdb->cmd, "SELECT JobId FROM Job WHERE Type='B' AND JobStatus IN ('T','W') AND " "ClientId=%s ORDER BY StartTime DESC LIMIT 1", edit_int64(jr->ClientId, ed1)); } } else { Mmsg1(&mdb->errmsg, _("Unknown Job level=%d\n"), jr->JobLevel); db_unlock(mdb); return false; } Dmsg1(100, "Query: %s\n", mdb->cmd); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { db_unlock(mdb); return false; } if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd); sql_free_result(mdb); db_unlock(mdb); return false; } jr->JobId = str_to_int64(row[0]); sql_free_result(mdb); Dmsg1(100, "db_get_last_jobid: got JobId=%d\n", jr->JobId); if (jr->JobId <= 0) { Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd); db_unlock(mdb); return false; } db_unlock(mdb); return true; }
/* * If VolumeName is non-zero, list the record for that Volume * otherwise, list the Volumes in the Pool specified by PoolId */ void db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, OUTPUT_FORMATTER *sendit, e_list_type type) { char ed1[50]; char esc[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); mdb->db_escape_string(jcr, esc, mdbr->VolumeName, strlen(mdbr->VolumeName)); if (type == VERT_LIST) { if (mdbr->VolumeName[0] != 0) { Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId," "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs," "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention," "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger," "EndFile,EndBlock,LabelType,StorageId,DeviceId," "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, " "Comment" " FROM Media WHERE Media.VolumeName='%s'", esc); } else { Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId," "MediaType,FirstWritten,LastWritten,LabelDate,VolJobs," "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Enabled,Recycle,VolRetention," "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger," "EndFile,EndBlock,LabelType,StorageId,DeviceId," "LocationId,RecycleCount,InitialWrite,ScratchPoolId,RecyclePoolId, " "Comment" " FROM Media WHERE Media.PoolId=%s ORDER BY MediaId", edit_int64(mdbr->PoolId, ed1)); } } else { if (mdbr->VolumeName[0] != 0) { Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled," "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten " "FROM Media WHERE Media.VolumeName='%s'", esc); } else { Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolStatus,Enabled," "VolBytes,VolFiles,VolRetention,Recycle,Slot,InChanger,MediaType,LastWritten " "FROM Media WHERE Media.PoolId=%s ORDER BY MediaId", edit_int64(mdbr->PoolId, ed1)); } } if (!QUERY_DB(jcr, mdb, mdb->cmd)) { goto bail_out; } sendit->object_start("media"); list_result(jcr, mdb, sendit, type); sendit->object_end("media"); sql_free_result(mdb); bail_out: db_unlock(mdb); }
/* Mark the file record as being visited during database * verify compare. Stuff JobId into the MarkId field */ bool db_mark_file_record(JCR *jcr, B_DB *mdb, FileId_t FileId, JobId_t JobId) { bool retval; char ed1[50], ed2[50]; db_lock(mdb); Mmsg(mdb->cmd, "UPDATE File SET MarkId=%s WHERE FileId=%s", edit_int64(JobId, ed1), edit_int64(FileId, ed2)); retval = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); return retval; }
/* * Update the Job record at end of Job * * Returns: 0 on failure * 1 on success */ int db_update_job_end_record(JCR *jcr, B_DB *mdb, JOB_DBR *jr) { char dt[MAX_TIME_LENGTH]; char rdt[MAX_TIME_LENGTH]; time_t ttime; struct tm tm; int stat; char ed1[30], ed2[30], ed3[50], ed4[50]; btime_t JobTDate; char PriorJobId[50]; if (jr->PriorJobId) { bstrncpy(PriorJobId, edit_int64(jr->PriorJobId, ed1), sizeof(PriorJobId)); } else { bstrncpy(PriorJobId, "0", sizeof(PriorJobId)); } ttime = jr->EndTime; (void)localtime_r(&ttime, &tm); strftime(dt, sizeof(dt), "%Y-%m-%d %H:%M:%S", &tm); if (jr->RealEndTime == 0) { jr->RealEndTime = jr->EndTime; } ttime = jr->RealEndTime; (void)localtime_r(&ttime, &tm); strftime(rdt, sizeof(rdt), "%Y-%m-%d %H:%M:%S", &tm); JobTDate = ttime; db_lock(mdb); Mmsg(mdb->cmd, "UPDATE Job SET JobStatus='%c',EndTime='%s'," "ClientId=%u,JobBytes=%s,ReadBytes=%s,JobFiles=%u,JobErrors=%u,VolSessionId=%u," "VolSessionTime=%u,PoolId=%u,FileSetId=%u,JobTDate=%s," "RealEndTime='%s',PriorJobId=%s,HasBase=%u,PurgedFiles=%u WHERE JobId=%s", (char)(jr->JobStatus), dt, jr->ClientId, edit_uint64(jr->JobBytes, ed1), edit_uint64(jr->ReadBytes, ed4), jr->JobFiles, jr->JobErrors, jr->VolSessionId, jr->VolSessionTime, jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), rdt, PriorJobId, jr->HasBase, jr->PurgedFiles, edit_int64(jr->JobId, ed3)); stat = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); return stat; }
/* * Update pool record -- pull info from current POOL resource */ static bool update_pool(UAContext *ua) { POOL_DBR pr; int id; POOL *pool; POOLMEM *query; char ed1[50]; pool = get_pool_resource(ua); if (!pool) { return false; } memset(&pr, 0, sizeof(pr)); bstrncpy(pr.Name, pool->name(), sizeof(pr.Name)); if (!get_pool_dbr(ua, &pr)) { return false; } set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE); /* update */ set_pooldbr_references(ua->jcr, ua->db, &pr, pool); id = db_update_pool_record(ua->jcr, ua->db, &pr); if (id <= 0) { ua->error_msg(_("db_update_pool_record returned %d. ERR=%s\n"), id, db_strerror(ua->db)); } query = get_pool_memory(PM_MESSAGE); Mmsg(query, list_pool, edit_int64(pr.PoolId, ed1)); db_list_sql_query(ua->jcr, ua->db, query, prtit, ua, 1, HORZ_LIST); free_pool_memory(query); ua->info_msg(_("Pool DB record updated from resource.\n")); return true; }
/* * Delete jobs (all records) from the catalog in groups of 1000 * at a time. */ void purge_job_list_from_catalog(UAContext *ua, del_ctx &del) { POOL_MEM jobids(PM_MESSAGE); char ed1[50]; for (int i=0; del.num_ids; ) { Dmsg1(150, "num_ids=%d\n", del.num_ids); pm_strcat(jobids, ""); for (int j=0; j<1000 && del.num_ids>0; j++) { del.num_ids--; if (del.JobId[i] == 0 || ua->jcr->JobId == del.JobId[i]) { Dmsg2(150, "skip JobId[%d]=%d\n", i, (int)del.JobId[i]); i++; continue; } if (*jobids.c_str() != 0) { pm_strcat(jobids, ","); } pm_strcat(jobids, edit_int64(del.JobId[i++], ed1)); Dmsg1(150, "Add id=%s\n", ed1); del.num_del++; } Dmsg1(150, "num_ids=%d\n", del.num_ids); purge_jobs_from_catalog(ua, jobids.c_str()); } }
/* * Prune Job stat records from the database. */ static bool prune_stats(UAContext *ua, utime_t retention) { char ed1[50]; char dt[MAX_TIME_LENGTH]; POOL_MEM query(PM_MESSAGE); utime_t now = (utime_t)time(NULL); db_lock(ua->db); Mmsg(query, "DELETE FROM JobHisto WHERE JobTDate < %s", edit_int64(now - retention, ed1)); db_sql_query(ua->db, query.c_str()); db_unlock(ua->db); ua->info_msg(_("Pruned Jobs from JobHisto in catalog.\n")); bstrutime(dt, sizeof(dt), now - retention); db_lock(ua->db); Mmsg(query, "DELETE FROM DeviceStats WHERE SampleTime < '%s'", dt); db_sql_query(ua->db, query.c_str()); db_unlock(ua->db); ua->info_msg(_("Pruned Statistics from DeviceStats in catalog.\n")); db_lock(ua->db); Mmsg(query, "DELETE FROM JobStats WHERE SampleTime < '%s'", dt); db_sql_query(ua->db, query.c_str()); db_unlock(ua->db); ua->info_msg(_("Pruned Statistics from JobStats in catalog.\n")); return true; }
/* * Delete files from a list of jobs in groups of 1000 * at a time. */ void purge_files_from_job_list(UAContext *ua, del_ctx &del) { POOL_MEM jobids(PM_MESSAGE); char ed1[50]; /* * OK, now we have the list of JobId's to be pruned, send them * off to be deleted batched 1000 at a time. */ for (int i=0; del.num_ids; ) { pm_strcat(jobids, ""); for (int j=0; j<1000 && del.num_ids>0; j++) { del.num_ids--; if (del.JobId[i] == 0 || ua->jcr->JobId == del.JobId[i]) { Dmsg2(150, "skip JobId[%d]=%d\n", i, (int)del.JobId[i]); i++; continue; } if (*jobids.c_str() != 0) { pm_strcat(jobids, ","); } pm_strcat(jobids, edit_int64(del.JobId[i++], ed1)); Dmsg1(150, "Add id=%s\n", ed1); del.num_del++; } purge_files_from_jobs(ua, jobids.c_str()); } }
static bool build_directory_tree(UAContext *ua, RESTORE_CTX *rx) { TREE_CTX tree; JobId_t JobId, last_JobId; char *p; bool OK = true; char ed1[50]; memset(&tree, 0, sizeof(TREE_CTX)); /* * Build the directory tree containing JobIds user selected */ tree.root = new_tree(rx->TotalFiles); tree.ua = ua; tree.all = rx->all; last_JobId = 0; /* * For display purposes, the same JobId, with different volumes may * appear more than once, however, we only insert it once. */ p = rx->JobIds; tree.FileEstimate = 0; if (get_next_jobid_from_list(&p, &JobId) > 0) { /* Use first JobId as estimate of the number of files to restore */ Mmsg(rx->query, uar_count_files, edit_int64(JobId, ed1)); if (!db_sql_query(ua->db, rx->query, restore_count_handler, (void *)rx)) { ua->error_msg("%s\n", db_strerror(ua->db)); } if (rx->found) { /* Add about 25% more than this job for over estimate */ tree.FileEstimate = rx->JobId + (rx->JobId >> 2); tree.DeltaCount = rx->JobId/50; /* print 50 ticks */ }
/* * Use pool and client specified by user to select jobs to prune * returns add_from string to add in FROM clause * add_where string to add in WHERE clause */ bool prune_set_filter(UAContext *ua, CLIENTRES *client, POOLRES *pool, utime_t period, POOL_MEM *add_from, POOL_MEM *add_where) { utime_t now; char ed1[50], ed2[MAX_ESCAPE_NAME_LENGTH]; POOL_MEM tmp(PM_MESSAGE); now = (utime_t)time(NULL); edit_int64(now - period, ed1); Dmsg3(150, "now=%lld period=%lld JobTDate=%s\n", now, period, ed1); Mmsg(tmp, " AND JobTDate < %s ", ed1); pm_strcat(*add_where, tmp.c_str()); db_lock(ua->db); if (client) { db_escape_string(ua->jcr, ua->db, ed2, client->name(), strlen(client->name())); Mmsg(tmp, " AND Client.Name = '%s' ", ed2); pm_strcat(*add_where, tmp.c_str()); pm_strcat(*add_from, " JOIN Client USING (ClientId) "); } if (pool) { db_escape_string(ua->jcr, ua->db, ed2, pool->name(), strlen(pool->name())); Mmsg(tmp, " AND Pool.Name = '%s' ", ed2); pm_strcat(*add_where, tmp.c_str()); /* Use ON() instead of USING for some old SQLite */ pm_strcat(*add_from, " JOIN Pool ON (Job.PoolId = Pool.PoolId) "); } Dmsg2(150, "f=%s w=%s\n", add_from->c_str(), add_where->c_str()); db_unlock(ua->db); return true; }
void db_list_files_for_job(JCR *jcr, B_DB *mdb, JobId_t jobid, OUTPUT_FORMATTER *sendit) { char ed1[50]; LIST_CTX lctx(jcr, mdb, sendit, NF_LIST); db_lock(mdb); /* * Stupid MySQL is NON-STANDARD ! */ if (db_get_type_index(mdb) == SQL_TYPE_MYSQL) { Mmsg(mdb->cmd, "SELECT CONCAT(Path.Path,Filename.Name) AS Filename " "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s " "UNION ALL " "SELECT PathId, FilenameId " "FROM BaseFiles JOIN File " "ON (BaseFiles.FileId = File.FileId) " "WHERE BaseFiles.JobId = %s" ") AS F, Filename,Path " "WHERE Filename.FilenameId=F.FilenameId " "AND Path.PathId=F.PathId", edit_int64(jobid, ed1), ed1); } else { Mmsg(mdb->cmd, "SELECT Path.Path||Filename.Name AS Filename " "FROM (SELECT PathId, FilenameId FROM File WHERE JobId=%s " "UNION ALL " "SELECT PathId, FilenameId " "FROM BaseFiles JOIN File " "ON (BaseFiles.FileId = File.FileId) " "WHERE BaseFiles.JobId = %s" ") AS F, Filename,Path " "WHERE Filename.FilenameId=F.FilenameId " "AND Path.PathId=F.PathId", edit_int64(jobid, ed1), ed1); } sendit->array_start("filenames"); if (!db_big_sql_query(mdb, mdb->cmd, list_result, &lctx)) { goto bail_out; } sendit->array_end("filenames"); sql_free_result(mdb); bail_out: db_unlock(mdb); }
/* * Update the Media Record Default values from Pool * * Returns: false on failure * true on success */ bool db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) { bool retval; char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50]; char esc[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); if (mr->VolumeName[0]) { mdb->db_escape_string(jcr, esc, mr->VolumeName, strlen(mr->VolumeName)); Mmsg(mdb->cmd, "UPDATE Media SET " "ActionOnPurge=%d,Recycle=%d,VolRetention=%s,VolUseDuration=%s," "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s," "MinBlocksize=%d,MaxBlocksize=%d" " WHERE VolumeName='%s'", mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1), edit_uint64(mr->VolUseDuration, ed2), mr->MaxVolJobs, mr->MaxVolFiles, edit_uint64(mr->MaxVolBytes, ed3), edit_uint64(mr->RecyclePoolId, ed4), mr->MinBlocksize, mr->MaxBlocksize, esc); } else { Mmsg(mdb->cmd, "UPDATE Media SET " "ActionOnPurge=%d,Recycle=%d,VolRetention=%s,VolUseDuration=%s," "MaxVolJobs=%u,MaxVolFiles=%u,MaxVolBytes=%s,RecyclePoolId=%s," "MinBlocksize=%d,MaxBlocksize=%d" " WHERE PoolId=%s", mr->ActionOnPurge, mr->Recycle,edit_uint64(mr->VolRetention, ed1), edit_uint64(mr->VolUseDuration, ed2), mr->MaxVolJobs, mr->MaxVolFiles, edit_uint64(mr->MaxVolBytes, ed3), edit_int64(mr->RecyclePoolId, ed4), mr->MinBlocksize, mr->MaxBlocksize, edit_int64(mr->PoolId, ed5)); } Dmsg1(400, "%s\n", mdb->cmd); retval = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); return retval; }
/* * List fileset */ void db_list_filesets(JCR *jcr, B_DB *mdb, JOB_DBR *jr, const char *range, OUTPUT_FORMATTER *sendit, e_list_type type) { char esc[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); if (jr->Name[0] != 0) { mdb->db_escape_string(jcr, esc, jr->Name, strlen(jr->Name)); Mmsg(mdb->cmd, "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, CreateTime, FileSetText " "FROM Job, FileSet " "WHERE Job.FileSetId = FileSet.FileSetId " "AND Job.Name='%s'%s", esc, range); } else if (jr->Job[0] != 0) { mdb->db_escape_string(jcr, esc, jr->Job, strlen(jr->Job)); Mmsg(mdb->cmd, "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, CreateTime, FileSetText " "FROM Job, FileSet " "WHERE Job.FileSetId = FileSet.FileSetId " "AND Job.Name='%s'%s", esc, range); } else if (jr->JobId != 0) { Mmsg(mdb->cmd, "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, CreateTime, FileSetText " "FROM Job, FileSet " "WHERE Job.FileSetId = FileSet.FileSetId " "AND Job.JobId='%s'%s", edit_int64(jr->JobId, esc), range); } else if (jr->FileSetId != 0) { Mmsg(mdb->cmd, "SELECT FileSetId, FileSet, MD5, CreateTime, FileSetText " "FROM FileSet " "WHERE FileSetId=%s", edit_int64(jr->FileSetId, esc)); } else { /* all records */ Mmsg(mdb->cmd, "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, CreateTime, FileSetText " "FROM FileSet ORDER BY FileSetId ASC%s", range); } if (!QUERY_DB(jcr, mdb, mdb->cmd)) { goto bail_out; } sendit->array_start("filesets"); list_result(jcr, mdb, sendit, type); sendit->array_end("filesets"); sql_free_result(mdb); bail_out: db_unlock(mdb); }
void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId, OUTPUT_FORMATTER *sendit, e_list_type type) { char ed1[50]; db_lock(mdb); if (type == VERT_LIST) { if (JobId > 0) { /* do by JobId */ Mmsg(mdb->cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName," "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock," "JobMedia.EndBlock " "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId " "AND JobMedia.JobId=%s", edit_int64(JobId, ed1)); } else { Mmsg(mdb->cmd, "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName," "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock," "JobMedia.EndBlock " "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId"); } } else { if (JobId > 0) { /* do by JobId */ Mmsg(mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex " "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId " "AND JobMedia.JobId=%s", edit_int64(JobId, ed1)); } else { Mmsg(mdb->cmd, "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex " "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId"); } } if (!QUERY_DB(jcr, mdb, mdb->cmd)) { goto bail_out; } sendit->array_start("jobmedia"); list_result(jcr, mdb, sendit, type); sendit->array_end("jobmedia"); sql_free_result(mdb); bail_out: db_unlock(mdb); }
/* * Find the most recent successful real end time for a job given. * * RealEndTime is returned in etime * Job name is returned in job (MAX_NAME_LENGTH) * * Returns: false on failure * true on success, jr is unchanged, but etime and job are set */ bool BDB::bdb_find_last_job_end_time(JCR *jcr, JOB_DBR *jr, POOLMEM **etime, char *job) { SQL_ROW row; char ed1[50], ed2[50]; char esc_name[MAX_ESCAPE_NAME_LENGTH]; bdb_lock(); bdb_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name)); pm_strcpy(etime, "0000-00-00 00:00:00"); /* default */ job[0] = 0; Mmsg(cmd, "SELECT RealEndTime, Job FROM Job WHERE JobStatus IN ('T','W') AND Type='%c' AND " "Level IN ('%c','%c','%c') AND Name='%s' AND ClientId=%s AND FileSetId=%s " "ORDER BY RealEndTime DESC LIMIT 1", jr->JobType, L_FULL, L_DIFFERENTIAL, L_INCREMENTAL, esc_name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2)); if (!QueryDB(jcr, cmd)) { Mmsg2(&errmsg, _("Query error for end time request: ERR=%s\nCMD=%s\n"), sql_strerror(), cmd); goto bail_out; } if ((row = sql_fetch_row()) == NULL) { sql_free_result(); Mmsg(errmsg, _("No prior backup Job record found.\n")); goto bail_out; } Dmsg1(100, "Got end time: %s\n", row[0]); pm_strcpy(etime, row[0]); bstrncpy(job, row[1], MAX_NAME_LENGTH); sql_free_result(); bdb_unlock(); return true; bail_out: bdb_unlock(); return false; }
static void update_volmaxfiles(UAContext *ua, char *val, MEDIA_DBR *mr) { POOL_MEM query(PM_MESSAGE); char ed1[50]; Mmsg(query, "UPDATE Media SET MaxVolFiles=%s WHERE MediaId=%s", val, edit_int64(mr->MediaId, ed1)); if (!db_sql_query(ua->db, query.c_str(), NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New max files is: %s\n"), val); } }
static void *do_batch(void *jcr) { JCR *bjcr = (JCR *)jcr; char data[1024]; int lineno = 0; struct ATTR_DBR ar; memset(&ar, 0, sizeof(ar)); btime_t begin = get_current_btime(); char *datafile = bjcr->where; FILE *fd = fopen(datafile, "r"); if (!fd) { Emsg1(M_ERROR_TERM, 0, _("Error opening datafile %s\n"), datafile); } while (fgets(data, sizeof(data)-1, fd)) { strip_trailing_newline(data); lineno++; if (verbose && ((lineno % 5000) == 1)) { printf("\r%i", lineno); } fill_attr(&ar, data); if (!db_create_attributes_record(bjcr, bjcr->db, &ar)) { Emsg0(M_ERROR_TERM, 0, _("Error while inserting file\n")); } } fclose(fd); db_write_batch_file_records(bjcr); btime_t end = get_current_btime(); P(mutex); char ed1[200], ed2[200]; printf("\rbegin = %s, end = %s\n", edit_int64(begin, ed1),edit_int64(end, ed2)); printf("Insert time = %sms\n", edit_int64((end - begin) / 10000, ed1)); printf("Create %u files at %.2f/s\n", lineno, (lineno / ((float)((end - begin) / 1000000)))); nb--; V(mutex); pthread_exit(NULL); return NULL; }
/* * Find the last job start time for the specified JobLevel * * StartTime is returned in stime * Job name is returned in job (MAX_NAME_LENGTH) * * Returns: false on failure * true on success, jr is unchanged, but stime and job are set */ bool db_find_last_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime, char *job, int JobLevel) { bool retval = false; SQL_ROW row; char ed1[50], ed2[50]; char esc_name[MAX_ESCAPE_NAME_LENGTH]; db_lock(mdb); mdb->db_escape_string(jcr, esc_name, jr->Name, strlen(jr->Name)); pm_strcpy(stime, "0000-00-00 00:00:00"); /* default */ job[0] = 0; Mmsg(mdb->cmd, "SELECT StartTime, Job FROM Job WHERE JobStatus IN ('T','W') AND Type='%c' AND " "Level='%c' AND Name='%s' AND ClientId=%s AND FileSetId=%s " "ORDER BY StartTime DESC LIMIT 1", jr->JobType, JobLevel, esc_name, edit_int64(jr->ClientId, ed1), edit_int64(jr->FileSetId, ed2)); if (!QUERY_DB(jcr, mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Query error for start time request: ERR=%s\nCMD=%s\n"), sql_strerror(mdb), mdb->cmd); goto bail_out; } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); Mmsg(mdb->errmsg, _("No prior Full backup Job record found.\n")); goto bail_out; } Dmsg1(100, "Got start time: %s\n", row[0]); pm_strcpy(stime, row[0]); bstrncpy(job, row[1], MAX_NAME_LENGTH); sql_free_result(mdb); retval = true; bail_out: db_unlock(mdb); return retval; }
bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr) { bool retval; char ed1[50]; db_lock(mdb); Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s", sr->AutoChanger, edit_int64(sr->StorageId, ed1)); retval = UPDATE_DB(jcr, mdb, mdb->cmd); db_unlock(mdb); return retval; }