@$(RMF) *~ 1 2 3 core core.* config.guess console.log console.sum
@$(RMF) examples/1 examples/2 examples/devices/1 examples/devices/2
@$(RMF) -r autom4te.cache
+ @find . -name .#* -exec $(RMF) {} \;
# clean for distribution
- Optimized bootstrap.
For 1.37:
-- Try to open a device on each Job if it was not opened
- when the SD started.
+- Add disk seeking on restore.
+- Add Python writable variable for changing the Priority,
+ Client, Storage, JobStatus (error), ...
+- SD Autochanger work
+ - Lock all devices when using changer script.
+ - Check if Volume is mounted on another device
+ - Find a free drive if Changer name used.
+- SD Python
+ - Solicit Events
+- FD Python
+ - Python script to save with Python, not save, save with Bacula.
+ - Python script to do backup.
- Windows restore:
data-fd: RestoreFiles.2004-12-07_15.56.42 Error:
> ..\findlib\../../findlib/create_file.c:275 Could not open e:/: ERR=Der
design.
- Create a new GUI chapter explaining all the GUI programs.
- Tell the "restore" user when browsing is no longer possible.
-- Add disk seeking on restore.
- Cancel command should include JobId in list of Jobs.
- Require restore via the restore command or make a restore Job
get the bootstrap file.
-- Add dump of VolSessionId/Time and FileIndex with bls.
- Make bootstrap file handle multiple MediaTypes (SD)
- Add offline tape command to Bacula console.
- Add performance testing hooks
-- Add Python writable variable for changing the Priority,
- Client, Storage, JobStatus (error), ...
- Document that Bootstrap files can be written with cataloging
turned off.
- Look at adding full Volume and Pool information to a Volume
- Implement Preben's suggestion to add
File System Types = ext2, ext3
to FileSets, thus simplifying backup of *all* local partitions.
+- Try to open a device on each Job if it was not opened
+ when the SD started.
+- Add dump of VolSessionId/Time and FileIndex with bls.
+
typedef char **POSTGRESQL_ROW;
typedef struct pg_field {
- char *name;
- int max_length;
- unsigned int type;
- unsigned int flags; // 1 == not null
+ char *name;
+ int max_length;
+ unsigned int type;
+ unsigned int flags; // 1 == not null
} POSTGRESQL_FIELD;
public:
DBId_t StorageId;
char Name[MAX_NAME_LENGTH]; /* Device name */
- DBId_t MediaTypeId; /* MediaType */
int AutoChanger; /* Set if autochanger */
+
+ /* Not in database */
+ bool created; /* set if created by db_create ... */
};
class MEDIATYPE_DBR {
int32_t Recycle; /* recycle yes/no */
int32_t Slot; /* slot in changer */
int32_t InChanger; /* Volume currently in changer */
+ DBId_t StorageId; /* Storage record Id */
uint32_t EndFile; /* Last file on volume */
uint32_t EndBlock; /* Last block on volume */
char VolStatus[20]; /* Volume status */
int db_update_job_end_record(JCR *jcr, B_DB *db, JOB_DBR *jr);
int db_update_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cr);
int db_update_pool_record(JCR *jcr, B_DB *db, POOL_DBR *pr);
+bool db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr);
int db_update_media_record(JCR *jcr, B_DB *db, MEDIA_DBR *mr);
int db_update_media_defaults(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr);
int db_update_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
bool
db_create_device_record(JCR *jcr, B_DB *mdb, DEVICE_DBR *dr)
{
- bool stat;
+ bool ok;
char ed1[30], ed2[30];
Dmsg0(200, "In create Device\n");
/* Must create it */
Mmsg(mdb->cmd,
-"INSERT INTO Device (Name,MediaTypeId,StorageId) "
-"VALUES ('%s',%s,%s)",
+"INSERT INTO Device (Name,MediaTypeId,StorageId) VALUES ('%s',%s,%s)",
dr->Name,
edit_uint64(dr->MediaTypeId, ed1),
- edit_uint64(dr->StorageId, ed2));
+ edit_int64(dr->StorageId, ed2));
Dmsg1(200, "Create Device: %s\n", mdb->cmd);
if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
Mmsg2(&mdb->errmsg, _("Create db Device record %s failed: ERR=%s\n"),
mdb->cmd, sql_strerror(mdb));
dr->DeviceId = 0;
- stat = false;
+ ok = false;
} else {
dr->DeviceId = sql_insert_id(mdb, _("Device"));
- stat = true;
+ ok = true;
}
db_unlock(mdb);
- return stat;
+ return ok;
}
+
+
/*
- * Create Unique storage record
+ * Create a Unique record for Storage -- no duplicates
* Returns: false on failure
- * true on success
+ * true on success with id in sr->StorageId
*/
-bool
-db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
+bool db_create_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
{
- bool stat;
+ SQL_ROW row;
+ bool ok;
- Dmsg0(200, "In create storage\n");
db_lock(mdb);
- Mmsg(mdb->cmd, "SELECT StorageId,Name FROM Storage WHERE Name='%s'", sr->Name);
- Dmsg1(200, "selectstorage: %s\n", mdb->cmd);
+ Mmsg(mdb->cmd, "SELECT StorageId,AutoChanger FROM Storage WHERE Name='%s'", sr->Name);
+ sr->StorageId = 0;
+ sr->created = false;
if (QUERY_DB(jcr, mdb, mdb->cmd)) {
mdb->num_rows = sql_num_rows(mdb);
- if (mdb->num_rows > 0) {
- Mmsg1(&mdb->errmsg, _("Storage record %s already exists\n"), sr->Name);
+ /* If more than one, report error, but return first row */
+ if (mdb->num_rows > 1) {
+ Mmsg1(&mdb->errmsg, _("More than one Storage record!: %d\n"), (int)(mdb->num_rows));
+ Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
+ }
+ if (mdb->num_rows >= 1) {
+ if ((row = sql_fetch_row(mdb)) == NULL) {
+ Mmsg1(&mdb->errmsg, _("error fetching Storage row: %s\n"), sql_strerror(mdb));
+ Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
+ sql_free_result(mdb);
+ db_unlock(mdb);
+ return false;
+ }
+ sr->StorageId = str_to_int64(row[0]);
+ sr->AutoChanger = atoi(row[1]); /* bool */
sql_free_result(mdb);
db_unlock(mdb);
- return false;
+ return true;
}
sql_free_result(mdb);
}
/* Must create it */
- Mmsg(mdb->cmd,
-"INSERT INTO Storage (Name,AutoChanger) "
-"VALUES ('%s',%d)",
- sr->Name,
- sr->AutoChanger);
- Dmsg1(200, "Create storage: %s\n", mdb->cmd);
+ Mmsg(mdb->cmd, "INSERT INTO Storage (Name,AutoChanger)"
+ " VALUES ('%s',%d)", sr->Name, sr->AutoChanger);
+
if (!INSERT_DB(jcr, mdb, mdb->cmd)) {
- Mmsg2(&mdb->errmsg, _("Create db storage record %s failed: ERR=%s\n"),
+ Mmsg2(&mdb->errmsg, _("Create DB Storage record %s failed. ERR=%s\n"),
mdb->cmd, sql_strerror(mdb));
- sr->StorageId = 0;
- stat = false;
+ Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
+ ok = false;
} else {
sr->StorageId = sql_insert_id(mdb, _("Storage"));
- stat = true;
+ sr->created = true;
+ ok = true;
}
db_unlock(mdb);
- return stat;
+ return ok;
}
}
-
-
/*
* Create Media record. VolumeName and non-zero Slot must be unique
*
db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
{
int stat;
- char ed1[30], ed2[30], ed3[30], ed4[30], ed5[30], ed6[50], ed7[50];
+ char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50], ed7[50], ed8[50];
struct tm tm;
db_lock(mdb);
"INSERT INTO Media (VolumeName,MediaType,PoolId,MaxVolBytes,VolCapacityBytes,"
"Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,"
"VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts,"
-"EndFile,EndBlock,LabelType) "
-"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d)",
+"EndFile,EndBlock,LabelType,StorageId) "
+"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0,%d,%s)",
mr->VolumeName,
mr->MediaType, mr->PoolId,
edit_uint64(mr->MaxVolBytes,ed1),
edit_uint64(mr->VolReadTime, ed6),
edit_uint64(mr->VolWriteTime, ed7),
mr->VolParts,
- mr->LabelType
+ mr->LabelType,
+ edit_int64(mr->StorageId, ed8)
);
return stat;
}
-
-
/*
* Create a Unique record for the client -- no duplicates
* Returns: 0 on failure
}
+
+
+
/*
* Create a Unique record for the counter -- no duplicates
* Returns: 0 on failure
"VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
"MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
"MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
- "EndFile,EndBlock,VolParts,LabelType,LabelDate "
+ "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId "
"FROM Media WHERE MediaId=%s",
edit_int64(mr->MediaId, ed1));
} else { /* find by name */
"VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes,"
"MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,"
"MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
- "EndFile,EndBlock,VolParts,LabelType,LabelDate "
+ "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId "
"FROM Media WHERE VolumeName='%s'", mr->VolumeName);
}
mr->LabelType = str_to_int64(row[26]);
bstrncpy(mr->cLabelDate, row[27]!=NULL?row[27]:"", sizeof(mr->cLabelDate));
mr->LabelDate = (time_t)str_to_utime(mr->cLabelDate);
+ mr->StorageId = str_to_int64(row[28]);
stat = mr->MediaId;
}
} else {
"VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
"VolCapacityBytes,VolStatus,Recycle,VolRetention,"
"VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
- "EndFile,EndBlock,VolParts,LabelType"
+ "EndFile,EndBlock,VolParts,LabelType,StorageId"
" FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName);
} else {
Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId,"
"VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites,"
"VolCapacityBytes,VolStatus,Recycle,VolRetention,"
"VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger,"
- "EndFile,EndBlock,VolParts,LabelType"
+ "EndFile,EndBlock,VolParts,LabelType,StorageId"
" FROM Media WHERE Media.PoolId=%s ORDER BY MediaId",
edit_int64(mdbr->PoolId, ed1));
}
return stat;
}
+bool
+db_update_storage_record(JCR *jcr, B_DB *mdb, STORAGE_DBR *sr)
+{
+ int stat;
+ char ed1[50];
+
+ db_lock(mdb);
+ Mmsg(mdb->cmd, "UPDATE Storage SET AutoChanger=%d WHERE StorageId=%s",
+ sr->AutoChanger, edit_int64(sr->StorageId, ed1));
+
+ stat = UPDATE_DB(jcr, mdb, mdb->cmd);
+ db_unlock(mdb);
+ return stat;
+}
+
+
/*
* Update the Media Record at end of Session
*
time_t ttime;
struct tm tm;
int stat;
- char ed1[30], ed2[30], ed3[30], ed4[30];
+ char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten);
strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
Mmsg(mdb->cmd, "UPDATE Media SET LabelDate='%s' "
"WHERE VolumeName='%s'", dt, mr->VolumeName);
- stat = UPDATE_DB(jcr, mdb, mdb->cmd);
+ UPDATE_DB(jcr, mdb, mdb->cmd);
}
if (mr->LastWritten != 0) {
ttime = mr->LastWritten;
localtime_r(&ttime, &tm);
strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm);
-
- Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
- "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
- "VolWrites=%u,MaxVolBytes=%s,LastWritten='%s',VolStatus='%s',"
- "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
- "LabelType=%d"
- " WHERE VolumeName='%s'",
- mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
- mr->VolMounts, mr->VolErrors, mr->VolWrites,
- edit_uint64(mr->MaxVolBytes, ed2), dt,
- mr->VolStatus, mr->Slot, mr->InChanger,
- edit_uint64(mr->VolReadTime, ed3),
- edit_uint64(mr->VolWriteTime, ed4),
- mr->VolParts,
- mr->LabelType,
- mr->VolumeName);
- } else {
- Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
- "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
- "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
- "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
- "LabelType=%d"
- " WHERE VolumeName='%s'",
- mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
- mr->VolMounts, mr->VolErrors, mr->VolWrites,
- edit_uint64(mr->MaxVolBytes, ed2),
- mr->VolStatus, mr->Slot, mr->InChanger,
- edit_uint64(mr->VolReadTime, ed3),
- edit_uint64(mr->VolWriteTime, ed4),
- mr->VolParts,
- mr->LabelType,
- mr->VolumeName);
+ Mmsg(mdb->cmd, "UPDATE Media Set LastWritten='%s' "
+ "WHERE VolumeName='%s'", dt, mr->VolumeName);
+ UPDATE_DB(jcr, mdb, mdb->cmd);
}
+ Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u,"
+ "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u,"
+ "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s',"
+ "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%d,"
+ "LabelType=%d,StorageId=%s"
+ " WHERE VolumeName='%s'",
+ mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1),
+ mr->VolMounts, mr->VolErrors, mr->VolWrites,
+ edit_uint64(mr->MaxVolBytes, ed2),
+ mr->VolStatus, mr->Slot, mr->InChanger,
+ edit_uint64(mr->VolReadTime, ed3),
+ edit_uint64(mr->VolWriteTime, ed4),
+ mr->VolParts,
+ mr->LabelType,
+ edit_int64(mr->StorageId, ed5),
+ mr->VolumeName);
+
Dmsg1(400, "%s\n", mdb->cmd);
stat = UPDATE_DB(jcr, mdb, mdb->cmd);
char ed1[50], ed2[50];
if (mr->InChanger != 0 && mr->Slot != 0) {
Mmsg(mdb->cmd, "UPDATE Media SET InChanger=0 WHERE "
- "Slot=%d AND PoolId=%s AND MediaId!=%s",
+ "Slot=%d AND StorageId=%s AND MediaId!=%s",
mr->Slot,
- edit_int64(mr->PoolId, ed1), edit_int64(mr->MediaId, ed2));
+ edit_int64(mr->StorageId, ed1), edit_int64(mr->MediaId, ed2));
Dmsg1(400, "%s\n", mdb->cmd);
UPDATE_DB(jcr, mdb, mdb->cmd);
}
* Check if it has expired, and if not update the DB. Note, if
* Volume has expired, has_volume_expired() will update the DB.
*/
- if (has_volume_expired(jcr, &mr)) {
- send_volume_info_to_storage_daemon(jcr, bs, &mr);
- } else if (db_update_media_record(jcr, jcr->db, &mr)) {
+ if (has_volume_expired(jcr, &mr) || db_update_media_record(jcr, jcr->db, &mr)) {
send_volume_info_to_storage_daemon(jcr, bs, &mr);
} else {
Jmsg(jcr, M_FATAL, 0, _("Catalog error updating Media record. %s"),
create_pool(NULL, db, pool, POOL_OP_UPDATE); /* update request */
}
- /* ***FIXME*** we need to update store and media_type records */
STORE *store;
foreach_res(store, R_STORAGE) {
STORAGE_DBR sr;
} else {
mr.MediaTypeId = 0;
}
- sr.MediaTypeId = mr.MediaTypeId;
bstrncpy(sr.Name, store->name(), sizeof(sr.Name));
sr.AutoChanger = store->autochanger;
db_create_storage_record(NULL, db, &sr);
+ store->StorageId = sr.StorageId; /* set storage Id */
+ if (!sr.created) { /* if not created, update it */
+ db_update_storage_record(NULL, db, &sr);
+ }
}
/* Loop over all counters, defining them in each database */
* Version $Id$
*/
/*
- Copyright (C) 2000-2004 Kern Sibbald and John Walker
+ Copyright (C) 2000-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
{"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
{"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
{"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
+ {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
+ {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
+ {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
{"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
{"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
{"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
break;
case R_STORAGE:
sendit(sock, "Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
-" DeviceName=%s MediaType=%s\n",
+" DeviceName=%s MediaType=%s StorageId=%s\n",
res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
res->res_store.MaxConcurrentJobs,
res->res_store.dev_name(),
- res->res_store.media_type);
+ res->res_store.media_type,
+ edit_int64(res->res_store.StorageId, ed1));
break;
case R_CATALOG:
sendit(sock, "Catalog: name=%s address=%s DBport=%d db_name=%s\n"
uint32_t NumConcurrentJobs; /* number of concurrent jobs running */
int enable_ssl; /* Use SSL */
+ int64_t StorageId; /* Set from Storage DB record */
+
char *dev_name() const;
char *name() const;
};
int replace; /* How (overwrite, ..) */
utime_t MaxRunTime; /* max run time in seconds */
utime_t MaxWaitTime; /* max blocking time in seconds */
+ utime_t FullMaxWaitTime; /* Max Full job wait time */
+ utime_t DiffMaxWaitTime; /* Max Differential job wait time */
+ utime_t IncMaxWaitTime; /* Max Incremental job wait time */
utime_t MaxStartDelay; /* max start delay in seconds */
int PrefixLinks; /* prefix soft links with Where path */
int PruneJobs; /* Force pruning of Jobs */
static bool job_check_maxwaittime(JCR *control_jcr, JCR *jcr)
{
bool cancel = false;
+ bool ok_to_cancel = false;
+ JOB *job = jcr->job;
- if (jcr->job->MaxWaitTime == 0) {
+ if (job->MaxWaitTime == 0 && job->FullMaxWaitTime == 0 &&
+ job->IncMaxWaitTime == 0 && job->DiffMaxWaitTime == 0) {
return false;
- }
- if ((watchdog_time - jcr->start_time) < jcr->job->MaxWaitTime) {
- Dmsg3(800, "Job %p (%s) with MaxWaitTime %d not expired\n",
- jcr, jcr->Job, jcr->job->MaxWaitTime);
+ }
+ if (jcr->JobLevel == L_FULL && job->FullMaxWaitTime != 0 &&
+ (watchdog_time - jcr->start_time) >= job->FullMaxWaitTime) {
+ ok_to_cancel = true;
+ } else if (jcr->JobLevel == L_DIFFERENTIAL && job->DiffMaxWaitTime != 0 &&
+ (watchdog_time - jcr->start_time) >= job->DiffMaxWaitTime) {
+ ok_to_cancel = true;
+ } else if (jcr->JobLevel == L_INCREMENTAL && job->IncMaxWaitTime != 0 &&
+ (watchdog_time - jcr->start_time) >= job->IncMaxWaitTime) {
+ ok_to_cancel = true;
+ } else if (job->MaxWaitTime != 0 &&
+ (watchdog_time - jcr->start_time) >= job->MaxWaitTime) {
+ ok_to_cancel = true;
+ }
+ if (!ok_to_cancel) {
return false;
}
Dmsg3(800, "Job %d (%s): MaxWaitTime of %d seconds exceeded, "
"checking status\n",
- jcr->JobId, jcr->Job, jcr->job->MaxWaitTime);
+ jcr->JobId, jcr->Job, job->MaxWaitTime);
switch (jcr->JobStatus) {
case JS_Created:
case JS_Blocked:
* Version $Id$
*/
/*
- Copyright (C) 2001-2004 Kern Sibbald and John Walker
+ Copyright (C) 2001-2005 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
* 2. Try finding a recycled volume
*/
ok = find_recycled_volume(jcr, InChanger, mr);
- Dmsg2(100, "find_recycled_volume %d FW=%d\n", ok, mr->FirstWritten);
+ Dmsg2(100, "find_recycled_volume %d FW=%d\n", ok, mr->FirstWritten);
if (!ok) {
/*
* 3. Try recycling any purged volume
continue; /* retry again accepting any volume */
}
}
- Dmsg2(200, "find_recycled_volume2 %d FW=%d\n", ok, mr->FirstWritten);
+ Dmsg2(200, "find_recycled_volume2 %d FW=%d\n", ok, mr->FirstWritten);
if (!ok && create) {
/*
- * 5. Try "creating" a new Volume
+ * 5. Try "creating" a new Volume
*/
ok = newVolume(jcr, mr);
}
*/
if (!ok && (jcr->pool->purge_oldest_volume ||
jcr->pool->recycle_oldest_volume)) {
- Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
+ Dmsg2(200, "No next volume found. PurgeOldest=%d\n RecyleOldest=%d",
jcr->pool->purge_oldest_volume, jcr->pool->recycle_oldest_volume);
/* Find oldest volume to recycle */
ok = db_find_next_volume(jcr, jcr->db, -1, InChanger, mr);
- Dmsg1(400, "Find oldest=%d\n", ok);
+ Dmsg1(400, "Find oldest=%d\n", ok);
if (ok) {
UAContext *ua;
- Dmsg0(400, "Try purge.\n");
+ Dmsg0(400, "Try purge.\n");
/*
* 5. Try to purging oldest volume only if not UA calling us.
*/
ua = new_ua_context(jcr);
if (jcr->pool->purge_oldest_volume && create) {
- Jmsg(jcr, M_INFO, 0, _("Purging oldest volume \"%s\"\n"), mr->VolumeName);
+ Jmsg(jcr, M_INFO, 0, _("Purging oldest volume \"%s\"\n"), mr->VolumeName);
ok = purge_jobs_from_volume(ua, mr);
/*
* 5. or try recycling the oldest volume
*/
} else if (jcr->pool->recycle_oldest_volume) {
- Jmsg(jcr, M_INFO, 0, _("Pruning oldest volume \"%s\"\n"), mr->VolumeName);
+ Jmsg(jcr, M_INFO, 0, _("Pruning oldest volume \"%s\"\n"), mr->VolumeName);
ok = prune_volume(ua, mr);
}
free_ua_context(ua);
if (ok) {
ok = recycle_volume(jcr, mr);
- Dmsg1(400, "Recycle after purge oldest=%d\n", ok);
+ Dmsg1(400, "Recycle after purge oldest=%d\n", ok);
}
}
}
if (strcmp(mr->VolStatus, "Append") == 0 && mr->VolJobs > 0) {
/* First handle Max Volume Bytes */
if ((mr->MaxVolBytes > 0 && mr->VolBytes >= mr->MaxVolBytes)) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. "
- "Marking Volume \"%s\" as Full.\n"), mr->VolumeName);
- bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus));
+ Jmsg(jcr, M_INFO, 0, _("Max Volume bytes exceeded. "
+ "Marking Volume \"%s\" as Full.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Full", sizeof(mr->VolStatus));
expired = true;
/* Now see if Volume should only be used once */
} else if (mr->VolBytes > 0 && jcr->pool->use_volume_once) {
- Jmsg(jcr, M_INFO, 0, _("Volume used once. "
- "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
- bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ Jmsg(jcr, M_INFO, 0, _("Volume used once. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
expired = true;
/* Now see if Max Jobs written to volume */
} else if (mr->MaxVolJobs > 0 && mr->MaxVolJobs <= mr->VolJobs) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
- bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ Jmsg(jcr, M_INFO, 0, _("Max Volume jobs exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
expired = true;
/* Now see if Max Files written to volume */
} else if (mr->MaxVolFiles > 0 && mr->MaxVolFiles <= mr->VolFiles) {
- Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
- bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ Jmsg(jcr, M_INFO, 0, _("Max Volume files exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
expired = true;
/* Finally, check Use duration expiration */
utime_t now = time(NULL);
/* See if Vol Use has expired */
if (mr->VolUseDuration <= (now - mr->FirstWritten)) {
- Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. "
- "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
- bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
+ Jmsg(jcr, M_INFO, 0, _("Max configured use duration exceeded. "
+ "Marking Volume \"%s\" as Used.\n"), mr->VolumeName);
+ bstrncpy(mr->VolStatus, "Used", sizeof(mr->VolStatus));
expired = true;
}
}
if (expired) {
/* Need to update media */
if (!db_update_media_record(jcr, jcr->db, mr)) {
- Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"),
+ Jmsg(jcr, M_ERROR, 0, _("Catalog error updating volume \"%s\". ERR=%s"),
mr->VolumeName, db_strerror(jcr->db));
}
}
*/
if (strcmp(mr->VolStatus, "Purged") == 0) {
if (recycle_volume(jcr, mr)) {
- Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
+ Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
*reason = NULL;
return;
} else {
- /* In principle this shouldn't happen */
- *reason = "and recycling of current volume failed";
+ /* In principle this shouldn't happen */
+ *reason = "and recycling of current volume failed";
return;
}
}
*/
if ((mr->LastWritten + mr->VolRetention) < (utime_t)time(NULL)
&& mr->Recycle && jcr->pool->recycle_current_volume
- && (strcmp(mr->VolStatus, "Full") == 0 ||
- strcmp(mr->VolStatus, "Used") == 0)) {
+ && (strcmp(mr->VolStatus, "Full") == 0 ||
+ strcmp(mr->VolStatus, "Used") == 0)) {
/*
* Attempt prune of current volume to see if we can
* recycle it for use.
if (ok) {
/* If fully purged, recycle current volume */
if (recycle_volume(jcr, mr)) {
- Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
+ Jmsg(jcr, M_INFO, 0, "Recycled current volume \"%s\"\n", mr->VolumeName);
*reason = NULL;
} else {
- *reason = "but should be Append, Purged or Recycle (recycling of the "
- "current volume failed)";
+ *reason = "but should be Append, Purged or Recycle (recycling of the "
+ "current volume failed)";
}
} else {
- *reason = "but should be Append, Purged or Recycle (cannot automatically "
- "recycle current volume, as it still contains unpruned data)";
+ *reason = "but should be Append, Purged or Recycle (cannot automatically "
+ "recycle current volume, as it still contains unpruned data)";
}
}
}
*/
/*
- Copyright (C) 2002-2004 Kern Sibbald and John Walker
+ Copyright (C) 2002-20054 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
bsendmsg(ua, "%s", db_strerror(ua->db));
}
- db_make_inchanger_unique(ua->jcr, ua->db, mr);
}
db_unlock(ua->db);
free_pool_memory(query);
memset(&mr, 0, sizeof(mr));
mr.Slot = vl->Slot;
mr.InChanger = 1;
+ mr.StorageId = store->StorageId;
/* Set InChanger to zero for this Slot */
db_lock(ua->db);
db_make_inchanger_unique(ua->jcr, ua->db, &mr);
bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
db_lock(ua->db);
if (db_get_media_record(ua->jcr, ua->db, &mr)) {
- if (mr.Slot != vl->Slot || !mr.InChanger) {
- mr.Slot = vl->Slot;
- mr.InChanger = 1;
- if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
- bsendmsg(ua, "%s", db_strerror(ua->db));
- } else {
- bsendmsg(ua, _(
- "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
- mr.VolumeName, mr.Slot);
- }
- } else {
- bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
- mr.VolumeName);
- }
- db_unlock(ua->db);
- continue;
+ if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store->StorageId) {
+ mr.Slot = vl->Slot;
+ mr.InChanger = 1;
+ mr.StorageId = store->StorageId;
+ if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+ bsendmsg(ua, "%s", db_strerror(ua->db));
+ } else {
+ bsendmsg(ua, _(
+ "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
+ mr.VolumeName, mr.Slot);
+ }
+ } else {
+ bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
+ mr.VolumeName);
+ }
+ db_unlock(ua->db);
+ continue;
} else {
- bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
+ bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
mr.VolumeName);
}
db_unlock(ua->db);
}
memset(&mr, 0, sizeof(mr));
mr.InChanger = 1;
+ mr.StorageId = store->StorageId;
db_lock(ua->db);
for (int i=1; i<max_slots; i++) {
if (slot_list[i]) {
if (mr.VolBytes != 0) {
bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
vl->Slot, mr.VolumeName);
- if (!mr.InChanger) {
- mr.InChanger = 1;
- if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
- bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
- }
+ mr.Slot = vl->Slot;
+ mr.InChanger = 1;
+ mr.StorageId = store->StorageId;
+ if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
+ bsendmsg(ua, "Error setting InChanger: ERR=%s", db_strerror(ua->db));
}
continue;
}
* record.
*/
if (pass == 2) {
+ DEVRES *dev;
+ int errstat;
switch (type) {
/* Resources not containing a resource */
case R_DIRECTOR:
}
/* we must explicitly copy the device alist pointer */
res->res_changer.device = res_all.res_changer.device;
+ foreach_alist(dev, res->res_changer.device) {
+ dev->changer_res = (AUTOCHANGER *)&res->res_changer;
+ }
+ if ((errstat = pthread_mutex_init(&dev->changer_res->changer_mutex, NULL)) != 0) {
+ berrno be;
+ Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
+ be.strerror(errstat));
+ }
break;
default:
printf("Unknown resource type %d\n", type);
};
typedef struct s_res_store STORES;
+class AUTOCHANGER {
+public:
+ RES hdr;
+ alist *device;
+ char *changer_name; /* Changer device name */
+ char *changer_command; /* Changer command -- external program */
+ pthread_mutex_t changer_mutex; /* One changer operation at a time */
+};
+
/* Device specific definitions */
class DEVRES {
public:
char *write_part_command; /* Write part command */
char *free_space_command; /* Free space command */
+ /* The following are set at runtime */
DEVICE *dev; /* Pointer to phyical dev -- set at runtime */
+ AUTOCHANGER *changer_res; /* pointer to changer res if any */
};
-class AUTOCHANGER {
-public:
- RES hdr;
- alist *device;
- char *changer_name; /* Changer device name */
- char *changer_command; /* Changer command -- external program */
-};
union URES {
DIRRES res_dir;
/* */
#undef VERSION
#define VERSION "1.37.4"
-#define BDATE "18 February 2005"
-#define LSMDATE "18Feb05"
+#define BDATE "20 February 2005"
+#define LSMDATE "20Feb05"
/* Debug flags */
#undef DEBUG