jobq.c mac.c mac_sql.c \
mountreq.c msgchan.c next_vol.c newvol.c \
recycle.c restore.c run_conf.c \
- scheduler.c \
+ scheduler.c store_mngr.c \
ua_acl.c ua_cmds.c ua_dotcmds.c \
ua_query.c ua_collect.c \
ua_input.c ua_label.c ua_output.c ua_prune.c \
bool do_admin_init(JCR *jcr)
{
- free_rstorage(jcr);
+ jcr->store_mngr->reset_rstorage();
if (!allow_duplicate_job(jcr)) {
return false;
}
return do_vbackup_init(jcr);
}
- free_rstorage(jcr); /* we don't read so release */
+ jcr->store_mngr->reset_rstorage();
/* If pool storage specified, use it instead of job storage */
- copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
+ jcr->store_mngr->set_wstorage(jcr->pool->storage, _("Pool resource"));
- if (!jcr->wstorage) {
+ if (!jcr->store_mngr->get_wstore()) {
Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n"));
return false;
}
*/
bool do_backup(JCR *jcr)
{
- int stat;
+ bool sd_job_started = false, wstore_group = false;
+ int stat, iter_no = 1;
BSOCK *fd, *sd;
STORE *store;
char *store_address;
*/
Dmsg0(110, "Open connection with storage daemon\n");
jcr->setJobStatus(JS_WaitSD);
- /*
- * Start conversation with Storage daemon
- */
- if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
- return false;
+
+ if (jcr->store_mngr->get_wstore_list()->size() != 1) {
+ wstore_group = true;
}
- /*
- * Now start a job with the Storage daemon
+
+ if (wstore_group) {
+ /* Apply policy for the write storage list */
+ jcr->store_mngr->apply_policy(true);
+ Jmsg(jcr, M_INFO, 0, _("Possible storage choices: %s\n"),
+ jcr->store_mngr->print_wlist());
+ iter_no = 2;
+ }
+
+ /* We are doing two iterations here:
+ * - First one with 'wait' set to false in start_storage_dameon_job() call
+ * to check if we can use any device from the list without waiting at all
+ * - Second iteration is performed when no device was avalable - this time we wait for a device to
+ * become available (hence setting wait to true in start_storage_daemon())
+ * Each iteration traverses storage list and try to reserve each. If any of the storages is ok to use,
+ * we stop the loops.
*/
- if (!start_storage_daemon_job(jcr, NULL, jcr->wstorage)) {
- return false;
+ for (int iter=0; iter<iter_no; iter++) {
+ if (wstore_group) {
+ if (iter == 0) {
+ Jmsg(jcr, M_INFO, 0, _("Trying to start job on any storage from the list without "
+ "waiting for busy devices first.\n"));
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("All devices are currently busy, need to wait at each try of storage reservation.\n"));
+ }
+ }
+
+ foreach_alist(store, jcr->store_mngr->get_wstore_list()) {
+ jcr->store_mngr->set_current_wstorage(store);
+
+ if (jcr->store_bsock) {
+ jcr->store_bsock->close();
+ }
+
+ /*
+ * Start conversation with Storage daemon
+ */
+ if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
+ Jmsg(jcr, M_INFO, 0, _("Failed connect to the storage: %s\n"),
+ jcr->store_mngr->get_wstore()->name());
+ continue;
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Connected to the storage: %s\n"),
+ jcr->store_mngr->get_wstore()->name());
+ }
+
+ alist wlist;
+ wlist.init(10, not_owned_by_alist);
+ wlist.append(store);
+
+ /*
+ * Now start a job with the Storage daemon with temporary, single-item list.
+ * We wait on the storage if there is only 1 storage defined,
+ * else 'iter' is used as a bool in start_storage_daemon_job(),
+ * because we have only 2 iterations (so 'iter' variable is either 0 or 1)
+ */
+ if (!start_storage_daemon_job(jcr, NULL, &wlist, wstore_group ? (bool)iter : true)) {
+ Jmsg(jcr, M_INFO, 0, _("Failed to start job on the storage: %s\n"),
+ jcr->store_mngr->get_wstore()->name());
+ continue;
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Started job on storage: %s\n"),
+ jcr->store_mngr->get_wstore()->name());
+ sd_job_started = true;
+ break;
+ }
+ }
+
+ if(sd_job_started) {
+ /* Now break from the outer loop as well */
+ break;
+ }
}
+
+ if(!sd_job_started) {
+ Jmsg(jcr, M_FATAL, 0, _("Failed to start job on any of the storages defined!\n"));
+ goto bail_out;
+ }
+
sd = jcr->store_bsock;
if (jcr->client) {
jcr->sd_calls_client = jcr->client->sd_calls_client;
send_snapshot_retention(jcr, jcr->snapshot_retention);
- store = jcr->wstore;
+ store = jcr->store_mngr->get_wstore();
if (jcr->sd_calls_client) {
if (jcr->FDVersion < 10) {
goto bail_out;
}
- store_address = jcr->wstore->address; /* dummy */
+ store_address = store->address; /* dummy */
store_port = 0; /* flag that SD calls FD */
} else {
/*
utime_t RunTime;
POOL_MEM base_info;
POOL_MEM vol_info;
+ STORE *wstore = jcr->store_mngr->get_wstore();
remove_dummy_jobmedia_records(jcr);
jcr->fileset->name(), jcr->FSCreateTime,
jcr->pool->name(), jcr->pool_source,
jcr->catalog->name(), jcr->catalog_source,
- jcr->wstore->name(), jcr->wstore_source,
+ wstore->name(), jcr->store_mngr->get_wsource(),
schedt,
sdt,
edt,
int can_create=0;
int Enabled, Recycle;
JobId_t JobId = 0;
+ STORE *wstore = jcr->store_mngr->get_wstore();
bmemset(&sdmr, 0, sizeof(sdmr));
bmemset(&jm, 0, sizeof(jm));
ok = db_get_pool_record(jcr, jcr->db, &pr);
if (ok) {
mr.PoolId = pr.PoolId;
- set_storageid_in_mr(jcr->wstore, &mr);
+ set_storageid_in_mr(wstore, &mr);
mr.ScratchPoolId = pr.ScratchPoolId;
ok = find_next_volume_for_append(jcr, &mr, index,
can_create?fnv_create_vol : fnv_no_create_vol,
*/
if (mr.PoolId != jcr->jr.PoolId) {
reason = _("not in Pool");
- } else if (strcmp(mr.MediaType, jcr->wstore->media_type) != 0) {
+ } else if (strcmp(mr.MediaType, jcr->store_mngr->get_wmedia_type()) != 0) {
reason = _("not correct MediaType");
} else {
/*
* However, do so only if we are writing the tape, i.e.
* the number of VolWrites has increased.
*/
- if (jcr->wstore && sdmr.VolWrites > mr.VolWrites) {
+ if (wstore && sdmr.VolWrites > mr.VolWrites) {
Dmsg2(050, "Update StorageId old=%d new=%d\n",
- mr.StorageId, jcr->wstore->StorageId);
+ mr.StorageId, wstore->StorageId);
/* Update StorageId after write */
- set_storageid_in_mr(jcr->wstore, &mr);
+ set_storageid_in_mr(wstore, &mr);
} else {
/* Nothing written, reset same StorageId */
set_storageid_in_mr(NULL, &mr);
if (!value) {
return bRC_Error;
}
+
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ STORE *wstore = jcr->store_mngr->get_wstore();
switch (var) {
case bDirVarJobId:
*((int *)value) = jcr->JobId;
Dmsg1(dbglvl, "Bacula: return bDirVarPool=%s\n", jcr->pool->hdr.name);
break;
case bDirVarStorage:
- if (jcr->wstore) {
- *((char **)value) = jcr->wstore->hdr.name;
- } else if (jcr->rstore) {
- *((char **)value) = jcr->rstore->hdr.name;
+ if (wstore) {
+ *((char **)value) = wstore->hdr.name;
+ } else if (rstore) {
+ *((char **)value) = rstore->hdr.name;
} else {
*((char **)value) = NULL;
ret=bRC_Error;
Dmsg1(dbglvl, "Bacula: return bDirVarStorage=%s\n", NPRT(*((char **)value)));
break;
case bDirVarWriteStorage:
- if (jcr->wstore) {
- *((char **)value) = jcr->wstore->hdr.name;
+ if (wstore) {
+ *((char **)value) = wstore->hdr.name;
} else {
*((char **)value) = NULL;
ret=bRC_Error;
Dmsg1(dbglvl, "Bacula: return bDirVarWriteStorage=%s\n", NPRT(*((char **)value)));
break;
case bDirVarReadStorage:
- if (jcr->rstore) {
- *((char **)value) = jcr->rstore->hdr.name;
+ if (rstore) {
+ *((char **)value) = rstore->hdr.name;
} else {
*((char **)value) = NULL;
ret=bRC_Error;
Dmsg1(dbglvl, "Bacula: return bDirVarCatalog=%s\n", jcr->catalog->hdr.name);
break;
case bDirVarMediaType:
- if (jcr->wstore) {
- *((char **)value) = jcr->wstore->media_type;
- } else if (jcr->rstore) {
- *((char **)value) = jcr->rstore->media_type;
+ if (wstore) {
+ *((char **)value) = wstore->media_type;
+ } else if (rstore) {
+ *((char **)value) = rstore->media_type;
} else {
*((char **)value) = NULL;
ret=bRC_Error;
static void dir_debug_print(JCR *jcr, FILE *fp)
{
fprintf(fp, "\twstore=%p rstore=%p wjcr=%p client=%p reschedule_count=%d SD_msg_chan_started=%d\n",
- jcr->wstore, jcr->rstore, jcr->wjcr, jcr->client, jcr->reschedule_count, (int)jcr->SD_msg_chan_started);
+ jcr->store_mngr->get_wstore(), jcr->store_mngr->get_rstore(), jcr->wjcr, jcr->client, jcr->reschedule_count, (int)jcr->SD_msg_chan_started);
}
/*********************************************************************
#include "lib/runscript.h"
#include "lib/breg.h"
#include "dird_conf.h"
+#include "store_mngr.h"
#define DIRECTOR_DAEMON 1
return globals->socket->get(timeout);
}
+/* Store a storage group policy */
+void store_storage_mngr(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+ lex_get_token(lc, T_STRING);
+ if (pass == 1) {
+ if (*(item->value)) {
+ scan_err5(lc, _("Attempt to redefine \"%s\" from \"%s\" to \"%s\" referenced on line %d : %s\n"),
+ item->name, *(item->value), lc->str, lc->line_no, lc->line);
+ return;
+ }
+
+ if (!StorageManager::check_policy(lc->str)) {
+ scan_err0(lc, _("Invalid storage policy!\n"));
+ return;
+ }
+
+ *(item->value) = bstrdup(lc->str);
+ }
+ scan_to_eol(lc);
+ set_bit(index, res_all.hdr.item_present);
+}
+
bool CLIENT::getBSOCK_state(POOLMEM *&buf)
{
P(globals_mutex);
{"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
{"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
{"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
+ {"StoragePolicy", store_storage_mngr, ITEM(res_job.storage_policy), 0, 0, 0},
{"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
{"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
{"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
if (res->res_job.run_cmds) {
delete res->res_job.run_cmds;
}
+ if (res->res_job.storage_policy) {
+ free(res->res_job.storage_policy);
+ }
if (res->res_job.storage) {
delete res->res_job.storage;
}
}
break;
case 'w':
- if (jcr->wstore) {
- return jcr->wstore->name();
+ {
+ STORE *wstore = jcr->store_mngr->get_wstore();
+ if (wstore) {
+ return wstore->name();
+ }
+ break;
}
- break;
case 'x':
return jcr->spool_data ? yes : no;
case 'D':
POOLMEM *store_source;
/* Methods */
- USTORE() { store = NULL; store_source = get_pool_memory(PM_MESSAGE);
- *store_source = 0; };
+ USTORE() { store = NULL;
+ store_source = get_pool_memory(PM_MESSAGE);
+ pm_strcpy(store_source, _("Unknown source"));
+ }
~USTORE() { destroy(); }
void set_source(const char *where);
void destroy();
CLIENT *client; /* Who to backup */
FILESET *fileset; /* What to backup -- Fileset */
alist *storage; /* Where is device -- list of Storage to be used */
+ char *storage_policy; /* Storage policy (e.g. round robin, least used...) */
POOL *pool; /* Where is media -- Media Pool */
POOL *next_pool; /* Next Pool for Copy/Migrate/VirtualFull */
POOL *full_pool; /* Pool for Full backups */
#define GetFileSetResWithName(x) ((FILESET *)GetResWithName(R_FILESET, (x)))
#define GetCatalogResWithName(x) ((CAT *)GetResWithName(R_CATALOG, (x)))
+/* Director daemon's specific */
+void store_storage_mngr(LEX *lc, RES_ITEM *item, int index, int pass);
+
/* Imported subroutines */
void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
const char *str = " ";
char buf[20];
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ STORE *wstore = jcr->store_mngr->get_wstore();
switch (code) {
case 1: /* Job */
str = jcr->job->name();
str = jcr->pool->name();
break;
case 9: /* Storage */
- if (jcr->wstore) {
- str = jcr->wstore->name();
+ if (wstore) {
+ str = wstore->name();
} else {
- str = jcr->rstore->name();
+ str = rstore->name();
}
break;
case 10: /* Catalog */
str = jcr->catalog->name();
break;
case 11: /* MediaType */
- if (jcr->wstore) {
- str = jcr->wstore->media_type;
+ if (wstore) {
+ str = wstore->media_type;
} else {
- str = jcr->rstore->media_type;
+ str = rstore->media_type;
}
break;
case 12: /* JobName */
{
FILESET *fileset = jcr->fileset;
BSOCK *fd = jcr->file_bsock;
- STORE *store = jcr->wstore;
+ STORE *store = jcr->store_mngr->get_wstore();
int num;
bool include = true;
static bool job_check_maxwaittime(JCR *jcr);
static bool job_check_maxruntime(JCR *jcr);
static bool job_check_maxrunschedtime(JCR *jcr);
+static void set_jcr_default_store(JCR *jcr, JOB *job);
/* Imported subroutines and variables */
extern void term_scheduler();
bool setup_job(JCR *jcr)
{
int errstat;
+ alist *rlist;
jcr->lock();
Dsm_check(100);
goto bail_out;
}
- if (jcr->JobReads() && !jcr->rstorage) {
- if (jcr->job->storage) {
- copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
- } else {
- copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
- }
+ rlist = jcr->store_mngr->get_rstore_list();
+ if (jcr->JobReads() && rlist->empty()) {
+ set_jcr_default_store(jcr, jcr->job);
}
if (!jcr->JobReads()) {
- free_rstorage(jcr);
+ jcr->store_mngr->reset_rstorage();
}
/*
static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
{
if (jcr->store_bsock) {
- if (jcr->rstorage) {
- copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
+ if (jcr->store_mngr->get_rstore()) {
+ ua->jcr->store_mngr->set_wstorage(jcr->store_mngr->get_rstore_list(), _("Job resource"));
} else {
- copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
+ ua->jcr->store_mngr->set_wstorage(jcr->store_mngr->get_wstore_list(), _("Job resource"));
}
} else {
- USTORE store;
- if (jcr->rstorage) {
- store.store = jcr->rstore;
+ STORE *store;
+ if (jcr->store_mngr->get_rstore()) {
+ store = jcr->store_mngr->get_rstore();
} else {
- store.store = jcr->wstore;
+ store = jcr->store_mngr->get_wstore();
}
- set_wstorage(ua->jcr, &store);
+ ua->jcr->store_mngr->set_wstorage(store, "Job resource");
}
- if (!ua->jcr->wstore) {
- ua->error_msg(_("Failed to select Storage daemon.\n"));
+ STORE *wstore = ua->jcr->store_mngr->get_wstore();
+ if (!wstore) {
+ ua->error_msg(_("Failed to select Storage daemon for jobid: %d.\n"), jcr->JobId);
return false;
}
}
Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
- ua->jcr->wstore->name(), ua->jcr, jcr);
+ wstore->name(), ua->jcr, jcr);
BSOCK *sd = ua->jcr->store_bsock;
sd->fsend("%s Job=%s\n", cmd, jcr->Job);
/* At this time, we can't really guess the storage name from
* the job record
*/
- store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
- if (!store.store) {
+ if (get_storage_resource(ua, &store, false/*no default*/, true/*unique*/)) {
goto bail_out;
}
- set_wstorage(jcr, &store);
+ jcr->store_mngr->set_wstorage(store.store, store.store_source);
cancel_sd_job(ua, "cancel", jcr);
bail_out:
ua->jcr = control_jcr;
if (jcr->store_bsock) {
- if (!ua->jcr->wstorage) {
- if (jcr->rstorage) {
- copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
+ alist *wlist = ua->jcr->store_mngr->get_wstore_list();
+ if (wlist->empty()) {
+ alist *rlist = jcr->store_mngr->get_rstore_list();
+ if (!rlist->empty()) {
+ ua->jcr->store_mngr->set_wstorage(jcr->store_mngr->get_rstore_list(), _("Job resource"));
} else {
- copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
+ ua->jcr->store_mngr->set_wstorage(jcr->store_mngr->get_wstore_list(), _("Job resource"));
}
} else {
- USTORE store;
- if (jcr->rstorage) {
- store.store = jcr->rstore;
+ STORE *store;
+ if (jcr->store_mngr->get_rstore()) {
+ store = jcr->store_mngr->get_rstore();
} else {
- store.store = jcr->wstore;
+ store = jcr->store_mngr->get_wstore();
}
- set_wstorage(ua->jcr, &store);
+ ua->jcr->store_mngr->set_wstorage(store, "Job cancellation");
}
if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
free_and_null_pool_memory(jcr->next_pool_source);
free_and_null_pool_memory(jcr->catalog_source);
free_and_null_pool_memory(jcr->rpool_source);
- free_and_null_pool_memory(jcr->wstore_source);
- free_and_null_pool_memory(jcr->rstore_source);
free_and_null_pool_memory(jcr->next_vol_list);
free_and_null_pool_memory(jcr->component_fname);
- /* Delete lists setup to hold storage pointers */
- free_rwstorage(jcr);
-
jcr->job_end_push.destroy();
+ delete jcr->store_mngr;
+
if (jcr->JobId != 0)
write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
}
/*
- * The Job storage definition must be either in the Job record
- * or in the Pool record. The Pool record overrides the Job
- * record.
+ * Override storage from run parameters if set.
*/
void get_job_storage(USTORE *store, JOB *job, RUN *run)
{
pm_strcpy(store->store_source, _("Run storage override"));
return;
}
- if (job->pool->storage) {
- store->store = (STORE *)job->pool->storage->first();
- pm_strcpy(store->store_source, _("Pool resource"));
+}
+
+static void set_jcr_default_store(JCR *jcr, JOB *job) {
+ if (job->storage) {
+ copy_rwstorage(jcr, job->storage, _("Job resource"));
} else {
- store->store = (STORE *)job->storage->first();
- pm_strcpy(store->store_source, _("Job resource"));
+ copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
}
}
}
jcr->JobPriority = job->Priority;
- /* Copy storage definitions -- deleted in dir_free_jcr above */
- if (job->storage) {
- copy_rwstorage(jcr, job->storage, _("Job resource"));
+
+ if (job->storage_policy) {
+ if (strcmp(job->storage_policy, "LeastUsed") == 0) {
+ jcr->store_mngr = New(LeastUsedStore());
+ }
} else {
- copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
+ jcr->store_mngr = New(SimpleStoreMngr());
}
+
+ set_jcr_default_store(jcr, job);
+
/* check if we run a restore */
if (jcr->getJobType() == JT_RESTORE && job->RestoreClient){
jcr->client = GetClientResWithName(jcr->job->RestoreClient);
void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
{
if (jcr->JobReads()) {
- copy_rstorage(jcr, storage, where);
+ jcr->store_mngr->set_rstore(storage, where);
}
- copy_wstorage(jcr, storage, where);
+ jcr->store_mngr->set_wstorage(storage, where);
}
return;
}
if (jcr->JobReads()) {
- set_rstorage(jcr, store);
- }
- set_wstorage(jcr, store);
-}
-
-void free_rwstorage(JCR *jcr)
-{
- free_rstorage(jcr);
- free_wstorage(jcr);
-}
-
-/*
- * Copy the storage definitions from an alist to the JCR
- */
-void copy_rstorage(JCR *jcr, alist *storage, const char *where)
-{
- if (storage) {
- STORE *st;
- if (jcr->rstorage) {
- delete jcr->rstorage;
- }
- jcr->rstorage = New(alist(10, not_owned_by_alist));
- foreach_alist(st, storage) {
- jcr->rstorage->append(st);
- }
- if (!jcr->rstore_source) {
- jcr->rstore_source = get_pool_memory(PM_MESSAGE);
- }
- pm_strcpy(jcr->rstore_source, where);
- if (jcr->rstorage) {
- jcr->rstore = (STORE *)jcr->rstorage->first();
- }
- }
-}
-
-
-/* Set storage override. Remove all previous storage */
-void set_rstorage(JCR *jcr, USTORE *store)
-{
- STORE *storage;
-
- if (!store->store) {
- return;
- }
- if (jcr->rstorage) {
- free_rstorage(jcr);
- }
- if (!jcr->rstorage) {
- jcr->rstorage = New(alist(10, not_owned_by_alist));
- }
- jcr->rstore = store->store;
- if (!jcr->rstore_source) {
- jcr->rstore_source = get_pool_memory(PM_MESSAGE);
- }
- pm_strcpy(jcr->rstore_source, store->store_source);
- foreach_alist(storage, jcr->rstorage) {
- if (store->store == storage) {
- return;
- }
- }
- /* Store not in list, so add it */
- jcr->rstorage->prepend(store->store);
-}
-
-void free_rstorage(JCR *jcr)
-{
- if (jcr->rstorage) {
- delete jcr->rstorage;
- jcr->rstorage = NULL;
- }
- jcr->rstore = NULL;
-}
-
-/*
- * Copy the storage definitions from an alist to the JCR
- */
-void copy_wstorage(JCR *jcr, alist *storage, const char *where)
-{
- if (storage) {
- STORE *st;
- if (jcr->wstorage) {
- delete jcr->wstorage;
- }
- jcr->wstorage = New(alist(10, not_owned_by_alist));
- foreach_alist(st, storage) {
- Dmsg1(100, "wstorage=%s\n", st->name());
- jcr->wstorage->append(st);
- }
- if (!jcr->wstore_source) {
- jcr->wstore_source = get_pool_memory(PM_MESSAGE);
- }
- pm_strcpy(jcr->wstore_source, where);
- if (jcr->wstorage) {
- jcr->wstore = (STORE *)jcr->wstorage->first();
- Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
- }
- }
-}
-
-
-/* Set storage override. Remove all previous storage */
-void set_wstorage(JCR *jcr, USTORE *store)
-{
- STORE *storage;
-
- if (!store->store) {
- return;
- }
- if (jcr->wstorage) {
- free_wstorage(jcr);
- }
- if (!jcr->wstorage) {
- jcr->wstorage = New(alist(10, not_owned_by_alist));
- }
- jcr->wstore = store->store;
- if (!jcr->wstore_source) {
- jcr->wstore_source = get_pool_memory(PM_MESSAGE);
- }
- pm_strcpy(jcr->wstore_source, store->store_source);
- Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
- foreach_alist(storage, jcr->wstorage) {
- if (store->store == storage) {
- return;
- }
- }
- /* Store not in list, so add it */
- jcr->wstorage->prepend(store->store);
-}
-
-void free_wstorage(JCR *jcr)
-{
- if (jcr->wstorage) {
- delete jcr->wstorage;
- jcr->wstorage = NULL;
+ jcr->store_mngr->set_rstore(store->store, store->store_source);
}
- jcr->wstore = NULL;
+ jcr->store_mngr->set_wstorage(store->store, store->store_source);
}
void create_clones(JCR *jcr)
static int start_server(jobq_t *jq);
static bool acquire_resources(JCR *jcr);
static bool reschedule_job(JCR *jcr, jobq_t *jq, jobq_item_t *je);
-static void dec_write_store(JCR *jcr);
/*
* Initialize a job queue
* put into the ready queue.
*/
if (jcr->acquired_resource_locks) {
- dec_read_store(jcr);
- dec_write_store(jcr);
+ jcr->store_mngr->dec_read_stores();
+ jcr->store_mngr->dec_write_stores();
update_client_numconcurrentjobs(jcr, -1);
jcr->job->incNumConcurrentJobs(-1);
jcr->acquired_resource_locks = false;
static bool reschedule_job(JCR *jcr, jobq_t *jq, jobq_item_t *je)
{
bool resched = false;
+ alist *store;
/*
* Reschedule the job if requested and possible
*/
njcr->diff_pool = jcr->diff_pool;
njcr->JobStatus = -1;
njcr->setJobStatus(jcr->JobStatus);
- if (jcr->rstore) {
- copy_rstorage(njcr, jcr->rstorage, _("previous Job"));
+ if (jcr->store_mngr->get_rstore()) {
+ store = jcr->store_mngr->get_rstore_list();
+ njcr->store_mngr->set_rstore(store, _("previous Job"));
} else {
- free_rstorage(njcr);
+ njcr->store_mngr->reset_rstorage();
}
- if (jcr->wstore) {
- copy_wstorage(njcr, jcr->wstorage, _("previous Job"));
+ if (jcr->store_mngr->get_wstore()) {
+ store = jcr->store_mngr->get_wstore_list();
+ njcr->store_mngr->set_wstorage(store, _("previous Job"));
} else {
- free_wstorage(njcr);
+ njcr->store_mngr->reset_wstorage();
}
njcr->messages = jcr->messages;
njcr->spool_data = jcr->spool_data;
return false;
}
#endif
- if (jcr->rstore) {
- Dmsg1(200, "Rstore=%s\n", jcr->rstore->name());
- if (!inc_read_store(jcr)) {
- Dmsg1(200, "Fail rncj=%d\n", jcr->rstore->getNumConcurrentJobs());
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ if (rstore) {
+ Dmsg1(200, "Rstore=%s\n", rstore->name());
+ if (!jcr->store_mngr->inc_read_stores(jcr)) {
+ Dmsg1(200, "Fail rncj=%d\n", rstore->getNumConcurrentJobs());
jcr->setJobStatus(JS_WaitStoreRes);
return false;
}
}
- if (jcr->wstore) {
- Dmsg1(200, "Wstore=%s\n", jcr->wstore->name());
- int num = jcr->wstore->getNumConcurrentJobs();
- if (num < jcr->wstore->MaxConcurrentJobs) {
- num = jcr->wstore->incNumConcurrentJobs(1);
- Dmsg1(200, "Inc wncj=%d\n", num);
- } else if (jcr->rstore) {
- dec_read_store(jcr);
- skip_this_jcr = true;
- } else {
- Dmsg1(200, "Fail wncj=%d\n", num);
- skip_this_jcr = true;
+ if (!jcr->store_mngr->inc_write_stores(jcr)) {
+ if (jcr->store_mngr->get_rstore()) {
+ jcr->store_mngr->dec_read_stores();
}
+ skip_this_jcr = true;
}
+
if (skip_this_jcr) {
jcr->setJobStatus(JS_WaitStoreRes);
return false;
update_client_numconcurrentjobs(jcr, 1);
} else {
/* Back out previous locks */
- dec_write_store(jcr);
- dec_read_store(jcr);
+ jcr->store_mngr->dec_write_stores();
+ jcr->store_mngr->dec_read_stores();
jcr->setJobStatus(JS_WaitClientRes);
return false;
}
jcr->job->incNumConcurrentJobs(1);
} else {
/* Back out previous locks */
- dec_write_store(jcr);
- dec_read_store(jcr);
+ jcr->store_mngr->dec_write_stores();
+ jcr->store_mngr->dec_read_stores();
update_client_numconcurrentjobs(jcr, -1);
jcr->setJobStatus(JS_WaitJobRes);
return false;
jcr->acquired_resource_locks = true;
return true;
}
-
-static pthread_mutex_t rstore_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-/*
- * Note: inc_read_store() and dec_read_store() are
- * called from select_rstore() in src/dird/restore.c
- */
-bool inc_read_store(JCR *jcr)
-{
- P(rstore_mutex);
- int num = jcr->rstore->getNumConcurrentJobs();
- int numread = jcr->rstore->getNumConcurrentReadJobs();
- int maxread = jcr->rstore->MaxConcurrentReadJobs;
- if (num < jcr->rstore->MaxConcurrentJobs &&
- (jcr->getJobType() == JT_RESTORE ||
- numread == 0 ||
- maxread == 0 || /* No limit set */
- numread < maxread)) /* Below the limit */
- {
- numread = jcr->rstore->incNumConcurrentReadJobs(1);
- num = jcr->rstore->incNumConcurrentJobs(1);
- Dmsg1(200, "Inc rncj=%d\n", num);
- V(rstore_mutex);
- return true;
- }
- V(rstore_mutex);
- return false;
-}
-
-void dec_read_store(JCR *jcr)
-{
- if (jcr->rstore) {
- P(rstore_mutex);
- jcr->rstore->incNumConcurrentReadJobs(-1);
- int num = jcr->rstore->incNumConcurrentJobs(-1);
- Dmsg1(200, "Dec rncj=%d\n", num);
- V(rstore_mutex);
- }
-}
-
-static void dec_write_store(JCR *jcr)
-{
- if (jcr->wstore) {
- int num = jcr->wstore->incNumConcurrentJobs(-1);
- Dmsg1(200, "Dec wncj=%d\n", num);
- }
-}
if (set_mac_next_pool(jcr, &pool)) {
/* If pool storage specified, use it for restore */
- copy_rstorage(wjcr, pool->storage, _("Pool resource"));
- copy_rstorage(jcr, pool->storage, _("Pool resource"));
+ wjcr->store_mngr->set_rstore(pool->storage, _("Pool resource"));
+ jcr->store_mngr->set_rstore(pool->storage, _("Pool resource"));
wjcr->pool = jcr->pool;
wjcr->next_pool = jcr->next_pool;
STORE *store;
char *store_address;
uint32_t store_port;
+ STORE *rstore = NULL;
+ STORE *wstore = NULL;
/*
* If wjcr is NULL, there is nothing to do for this job,
* Now separate the read and write storages. jcr has no wstor...
* they all go into wjcr.
*/
- free_rwstorage(wjcr);
- wjcr->rstore = NULL;
- wjcr->wstore = jcr->wstore;
- jcr->wstore = NULL;
- wjcr->wstorage = jcr->wstorage;
- jcr->wstorage = NULL;
+ wjcr->store_mngr->reset_rwstorage();
+ wjcr->store_mngr->set_wstorage(jcr->store_mngr->get_wstore_list(), _("MAC JOB"));
+ jcr->store_mngr->reset_wstorage();
/* TODO: See priority with bandwidth parameter */
if (jcr->job->max_bandwidth > 0) {
jcr->sd_calls_client = jcr->client->sd_calls_client;
}
+ rstore = jcr->store_mngr->get_rstore();
+ wstore = wjcr->store_mngr->get_wstore();
Dmsg2(dbglevel, "Read store=%s, write store=%s\n",
- ((STORE *)jcr->rstorage->first())->name(),
- ((STORE *)wjcr->wstorage->first())->name());
+ rstore->name(),
+ wstore->name());
/*
* Now start a job with the read Storage daemon sending the bsr.
* This call returns the sd_auth_key
*/
Dmsg1(200, "Start job with read (jcr) storage daemon. Jid=%d\n", jcr->JobId);
- if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL, /*send_bsr*/true)) {
+ if (!start_storage_daemon_job(jcr, jcr->store_mngr->get_rstore_list(), NULL, /*send_bsr*/true)) {
goto bail_out;
}
Dmsg0(150, "Read storage daemon connection OK\n");
* Now start a job with the write Storage daemon sending.
*/
Dmsg1(200, "Start Job with write (wjcr) storage daemon. Jid=%d\n", jcr->JobId);
- if (!start_storage_daemon_job(wjcr, NULL, wjcr->wstorage, /*no_send_bsr*/false)) {
+ if (!start_storage_daemon_job(wjcr, NULL, wjcr->store_mngr->get_wstore_list(), /*no_send_bsr*/false)) {
goto bail_out;
}
Dmsg0(150, "Write storage daemon connection OK\n");
}
/* Setup the storage address and port */
- store = wjcr->wstore;
+ store = wjcr->store_mngr->get_wstore();
if (store->SDDport == 0) {
store->SDDport = store->SDport;
}
*
* Send Storage daemon address to the writing SD
*/
- store = jcr->rstore;
+ store = jcr->store_mngr->get_rstore();
if (store->SDDport == 0) {
store->SDDport = store->SDport;
}
bail_out:
/* Put back jcr write storages for proper cleanup */
- jcr->wstorage = wjcr->wstorage;
- jcr->wstore = wjcr->wstore;
- wjcr->wstore = NULL;
- wjcr->wstorage = NULL;
+ jcr->store_mngr->set_wstorage(wjcr->store_mngr->get_wstore_list(), "rollback");
+ wjcr->store_mngr->reset_wstorage();
wjcr->file_bsock = NULL;
if (ok) {
jcr->FSCreateTime,
jcr->rpool?jcr->rpool->name():"*None*",
jcr->rpool_source,
- jcr->rstore?jcr->rstore->name():"*None*",
- NPRT(jcr->rstore_source),
+ jcr->store_mngr->get_rstore()?jcr->store_mngr->get_rstore()->name():"*None*",
+ NPRT(jcr->store_mngr->get_rsource()),
jcr->pool?jcr->pool->name():"*None*",
jcr->pool_source,
- jcr->wstore?jcr->wstore->name():"*None*",
- NPRT(jcr->wstore_source),
+ jcr->store_mngr->get_wstore()?jcr->store_mngr->get_wstore()->name():"*None*",
+ NPRT(jcr->store_mngr->get_wsource()),
jcr->catalog?jcr->catalog->name():"*None*",
jcr->catalog_source,
sdt,
}
/* If pool storage specified, use it instead of job storage for backup */
- copy_wstorage(jcr, next_pool->storage, source);
+ jcr->store_mngr->set_wstorage(next_pool->storage, source);
return true;
}
"rerunning=%d VolSessionId=%d VolSessionTime=%d sd_client=%d "
"Authorization=%s\n";
static char use_storage[] = "use storage=%s media_type=%s pool_name=%s "
- "pool_type=%s append=%d copy=%d stripe=%d\n";
+ "pool_type=%s append=%d copy=%d stripe=%d wait=%d\n";
static char use_device[] = "use device=%s\n";
//static char query_device[] = _("query device=%s");
BSOCK *open_sd_bsock(UAContext *ua)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
if (!is_bsock_open(ua->jcr->store_bsock)) {
ua->send_msg(_("Connecting to Storage daemon %s at %s:%d ...\n"),
BSOCK *sd = jcr->store_bsock;
STORE *store;
utime_t heart_beat;
+ STORE *wstore = jcr->store_mngr->get_wstore();
if (is_bsock_open(sd)) {
return true; /* already connected */
}
/* If there is a write storage use it */
- if (jcr->wstore) {
- store = jcr->wstore;
+ if (wstore) {
+ store = wstore;
} else {
- store = jcr->rstore;
+ store = jcr->store_mngr->get_rstore();
+ }
+
+ if (!store) {
+ Dmsg0(100, "No storage resource found in jcr!\n");
+ return false;
}
if (store->heartbeat_interval) {
/*
* Start a job with the Storage daemon
*/
-bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore, bool send_bsr)
+bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore, bool wait, bool send_bsr)
{
bool ok = true;
STORE *storage;
POOL_MEM job_name, client_name, fileset_name;
int copy = 0;
int stripe = 0;
+ int sleep = wait; /* 'wait' arg needs to be passed as an int through the network */
char ed1[30], ed2[30];
int sd_client;
}
bash_spaces(media_type);
sd->fsend(use_storage, store_name.c_str(), media_type.c_str(),
- pool_name.c_str(), pool_type.c_str(), 0, copy, stripe);
+ pool_name.c_str(), pool_type.c_str(), 0, copy, stripe, sleep);
Dmsg1(100, "rstore >stored: %s", sd->msg);
DEVICE *dev;
/* Loop over alternative storage Devices until one is OK */
pm_strcpy(media_type, storage->media_type);
bash_spaces(media_type);
sd->fsend(use_storage, store_name.c_str(), media_type.c_str(),
- pool_name.c_str(), pool_type.c_str(), 1, copy, stripe);
+ pool_name.c_str(), pool_type.c_str(), 1, copy, stripe, sleep);
Dmsg1(100, "wstore >stored: %s", sd->msg);
DEVICE *dev;
POOL_MEM err_msg;
if (sd->msg[0]) {
pm_strcpy(err_msg, sd->msg); /* save message */
- Jmsg(jcr, M_FATAL, 0, _("\n"
+ Jmsg(jcr, M_INFO, 0, _("\n"
" Storage daemon didn't accept Device \"%s\" because:\n %s"),
device_name.c_str(), err_msg.c_str()/* sd->msg */);
} else {
- Jmsg(jcr, M_FATAL, 0, _("\n"
+ Jmsg(jcr, M_INFO, 0, _("\n"
" Storage daemon didn't accept Device \"%s\" command.\n"),
device_name.c_str());
}
bool newVolume(JCR *jcr, MEDIA_DBR *mr, STORE *store, POOL_MEM &errmsg)
{
POOL_DBR pr;
+ STORE *wstore = jcr->store_mngr->get_wstore();
bmemset(&pr, 0, sizeof(pr));
mr->clear();
set_pool_dbr_defaults_in_media_dbr(mr, &pr);
jcr->VolumeName[0] = 0;
- bstrncpy(mr->MediaType, jcr->wstore->media_type, sizeof(mr->MediaType));
+ bstrncpy(mr->MediaType, wstore->media_type, sizeof(mr->MediaType));
generate_plugin_event(jcr, bDirEventNewVolume); /* return void... */
if (jcr->VolumeName[0] && is_volume_name_legal(NULL, jcr->VolumeName)) {
bstrncpy(mr->VolumeName, jcr->VolumeName, sizeof(mr->VolumeName));
int retry = 0;
bool ok;
bool InChanger;
- STORE *store = jcr->wstore;
+ STORE *store = jcr->store_mngr->get_wstore();
bstrncpy(mr->MediaType, store->media_type, sizeof(mr->MediaType));
Dmsg6(dbglvl, "find_next_vol_for_append: JobId=%u PoolId=%d, MediaType=%s index=%d create=%d prune=%d\n",
extern void update_job_end(JCR *jcr, int TermCode);
extern void copy_rwstorage(JCR *jcr, alist *storage, const char *where);
extern void set_rwstorage(JCR *jcr, USTORE *store);
-extern void free_rwstorage(JCR *jcr);
-extern void copy_wstorage(JCR *jcr, alist *storage, const char *where);
-extern void set_wstorage(JCR *jcr, USTORE *store);
-extern void free_wstorage(JCR *jcr);
-extern void copy_rstorage(JCR *jcr, alist *storage, const char *where);
-extern void set_rstorage(JCR *jcr, USTORE *store);
-extern void free_rstorage(JCR *jcr);
extern bool setup_job(JCR *jcr);
extern void create_clones(JCR *jcr);
extern int create_restore_bootstrap_file(JCR *jcr);
extern void close_sd_bsock(UAContext *ua);
extern bool connect_to_storage_daemon(JCR *jcr, int retry_interval,
int max_retry_time, int verbose);
-extern bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore,
+extern bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore, bool wait,
bool send_bsr=false);
extern bool start_storage_daemon_message_thread(JCR *jcr);
extern int bget_dirmsg(BSOCK *bs);
int do_alist_prompt(UAContext *ua, const char *automsg, const char *msg,
alist *selected);
CAT *get_catalog_resource(UAContext *ua);
-STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique=false);
+bool get_storage_resource(UAContext *ua, USTORE *ustore, bool use_default, bool unique=false);
int get_storage_drive(UAContext *ua, STORE *store);
int get_storage_slot(UAContext *ua, STORE *store);
int get_media_type(UAContext *ua, char *MediaType, int max_media);
if (!jcr->RestoreBootstrap) {
return false;
}
- bstrncpy(info.storage, jcr->rstore->name(), MAX_NAME_LENGTH);
+ bstrncpy(info.storage, jcr->store_mngr->get_rstore()->name(), MAX_NAME_LENGTH);
bs = bfopen(jcr->RestoreBootstrap, "rb");
if (!bs) {
return true;
}
/* same name */
- if (!strcmp(new_one, jcr->rstore->name())) {
+ if (!strcmp(new_one, jcr->store_mngr->get_rstore()->name())) {
return true;
}
new_store = (STORE *)GetResWithName(R_STORAGE, new_one);
/* if Port and Hostname/IP are same, we are talking to the same
* Storage Daemon
*/
- if (jcr->rstore->SDport != new_store->SDport ||
- strcmp(jcr->rstore->address, new_store->address))
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ if (rstore->SDport != new_store->SDport ||
+ strcmp(rstore->address, new_store->address))
{
return false;
}
*/
static bool select_rstore(JCR *jcr, bootstrap_info &info)
{
- USTORE ustore;
+ STORE *store;
int i;
- if (!strcmp(jcr->rstore->name(), info.storage)) {
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ if (!strcmp(rstore->name(), info.storage)) {
return true; /* same SD nothing to change */
}
- if (!(ustore.store = (STORE *)GetResWithName(R_STORAGE,info.storage))) {
+ if (!(store = (STORE *)GetResWithName(R_STORAGE,info.storage))) {
Jmsg(jcr, M_FATAL, 0,
_("Could not get storage resource '%s'.\n"), info.storage);
jcr->setJobStatus(JS_ErrorTerminated);
/*
* release current read storage and get a new one
*/
- dec_read_store(jcr);
- free_rstorage(jcr);
- set_rstorage(jcr, &ustore);
+ jcr->store_mngr->dec_read_stores();
+ jcr->store_mngr->set_rstore(store, _("Job resource"));
jcr->setJobStatus(JS_WaitSD);
/*
* Wait for up to 6 hours to increment read stoage counter
*/
for (i=0; i < MAX_TRIES; i++) {
/* try to get read storage counter incremented */
- if (inc_read_store(jcr)) {
+ if (jcr->store_mngr->inc_read_stores(jcr)) {
jcr->setJobStatus(JS_Running);
return true;
}
bmicrosleep(10, 0); /* sleep 10 secs */
if (job_canceled(jcr)) {
- free_rstorage(jcr);
+ jcr->store_mngr->reset_rstorage();
return false;
}
}
/* Failed to inc_read_store() */
- free_rstorage(jcr);
+ jcr->store_mngr->reset_rstorage();
Jmsg(jcr, M_FATAL, 0,
_("Could not acquire read storage lock for \"%s\""), info.storage);
return false;
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
+ if (!start_storage_daemon_job(jcr, jcr->store_mngr->get_rstore_list(), NULL, true /* wait */)) {
goto bail_out;
}
goto bail_out;
}
+ STORE *rstore = jcr->store_mngr->get_rstore();
+
if (jcr->sd_calls_client) {
/*
* SD must call "client" i.e. FD
goto bail_out;
}
- store_address = jcr->rstore->address; /* dummy */
+ store_address = rstore->address; /* dummy */
store_port = 0; /* flag that SD calls FD */
} else {
* then wait for File daemon to make connection
* with Storage daemon.
*/
- if (jcr->rstore->SDDport == 0) {
- jcr->rstore->SDDport = jcr->rstore->SDport;
+ if (rstore->SDDport == 0) {
+ rstore->SDDport = rstore->SDport;
}
- store_address = get_storage_address(jcr->client, jcr->rstore);
- store_port = jcr->rstore->SDDport;
+ store_address = get_storage_address(jcr->client, rstore);
+ store_port = rstore->SDDport;
}
/* TLS Requirement */
- if (jcr->rstore->tls_enable) {
- if (jcr->rstore->tls_require) {
+ if (rstore->tls_enable) {
+ if (rstore->tls_require) {
tls_need = BNET_TLS_REQUIRED;
} else {
tls_need = BNET_TLS_OK;
JOB_DBR rjr; /* restore job record */
int stat;
- free_wstorage(jcr); /* we don't write */
+ jcr->store_mngr->reset_wstorage();
if (!allow_duplicate_job(jcr)) {
goto bail_out;
delete jcr->plugin_config;
jcr->plugin_config = NULL;
}
- free_wstorage(jcr);
+ jcr->store_mngr->reset_wstorage();
return true;
}
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2020 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+
+#include "bacula.h"
+#include "dird.h"
+
+storage::storage() {
+ list = New(alist(10, not_owned_by_alist));
+ source = get_pool_memory(PM_MESSAGE);
+ list_str = get_pool_memory(PM_MESSAGE);
+ *source = 0;
+ store = NULL;
+ mutex = PTHREAD_MUTEX_INITIALIZER;
+}
+
+storage::~storage() {
+ store = NULL;
+ if (list) {
+ delete list;
+ list = NULL;
+ }
+ if (source) {
+ free_and_null_pool_memory(source);
+ }
+ if (list_str) {
+ free_and_null_pool_memory(list_str);
+ }
+}
+
+void storage::set_rw(bool write) {
+ P(mutex);
+ this->write = write;
+ V(mutex);
+}
+
+alist *storage::get_list() {
+ return list;
+}
+
+const char *storage::get_source() const {
+ return source;
+}
+
+const char *storage::get_media_type() const {
+ return store->media_type;
+}
+
+void storage::set(STORE *storage, const char *source) {
+ if (!storage) {
+ return;
+ }
+
+ P(mutex);
+
+ reset();
+
+ list->append(storage);
+
+ store = storage;
+ if (!source) {
+ pm_strcpy(this->source, _("Not specified"));
+ } else {
+ pm_strcpy(this->source, source);
+ }
+
+ V(mutex);
+}
+
+/* Set storage override. Remove all previous storage */
+void storage::set(alist *storage, const char *source) {
+ if (!storage) {
+ return;
+ }
+
+ P(mutex);
+
+ reset();
+
+ STORE *s;
+ foreach_alist(s, storage) {
+ list->append(s);
+ }
+
+ store = (STORE *)list->first();
+ if (!source) {
+ pm_strcpy(this->source, _("Not specified"));
+ } else {
+ pm_strcpy(this->source, source);
+ }
+
+ V(mutex);
+}
+
+void storage::reset() {
+ store = NULL;
+ while (list->size()) {
+ list->remove(0);
+ }
+ *source = 0;
+ *list_str = 0;
+}
+
+/* Set custom storage for next usage (it needs to be an item from the current store list) */
+bool storage::set_current_storage(STORE *storage) {
+ if (!storage) {
+ return false;
+ }
+
+ P(mutex);
+
+ STORE *s;
+ foreach_alist(s, list) {
+ if (s == storage) {
+ store = storage;
+ V(mutex);
+ return true;
+ }
+ }
+
+ V(mutex);
+ return false;
+}
+
+bool storage::inc_rstores(JCR *jcr) {
+ if (list->empty()) {
+ return true;
+ }
+
+ P(mutex);
+ int num = store->getNumConcurrentJobs();
+ int numread = store->getNumConcurrentReadJobs();
+ int maxread = store->MaxConcurrentReadJobs;
+ if (num < store->MaxConcurrentJobs &&
+ (jcr->getJobType() == JT_RESTORE ||
+ numread == 0 ||
+ maxread == 0 || /* No limit set */
+ numread < maxread)) /* Below the limit */
+ {
+ numread = store->incNumConcurrentReadJobs(1);
+ num = store->incNumConcurrentJobs(1);
+ Dmsg1(200, "Inc rncj=%d\n", num);
+ V(mutex);
+ return true;
+ }
+ V(mutex);
+ return false;
+}
+
+bool storage::inc_wstores(JCR *jcr) {
+ STORE *store;
+ bool ret;
+ if (list->empty()) {
+ return true;
+ }
+
+ P(mutex);
+
+ /* Create a temp copy of wstore list */
+ alist tmp_list(10, not_owned_by_alist);
+ foreach_alist(store, list) {
+ tmp_list.append(store);
+ }
+
+ /* Reset write list */
+ list->destroy();
+ list->init(10, not_owned_by_alist);
+
+ foreach_alist(store, &tmp_list) {
+ Dmsg1(200, "Wstore=%s\n", store->name());
+ int num = store->getNumConcurrentJobs();
+ if (num < store->MaxConcurrentJobs) {
+ num = store->incNumConcurrentJobs(1);
+ Dmsg1(200, "Inc wncj=%d\n", num);
+ list->append(store);
+ }
+ }
+
+ if (!list->empty()) {
+ ret = true;
+ } else {
+ /* Failed to increment counter in at least one storage */
+ ret = false;
+ }
+
+ V(mutex);
+ return ret;
+}
+
+bool storage::inc_stores(JCR *jcr) {
+ if (write) {
+ return inc_wstores(jcr);
+ } else {
+ return inc_rstores(jcr);
+ }
+}
+
+void storage::dec_stores() {
+ if (list->empty()) {
+ return;
+ }
+
+ P(mutex);
+ STORE *store;
+ foreach_alist(store, list) {
+ int num = store->incNumConcurrentJobs(-1);
+ Dmsg1(200, "Dec wncj=%d\n", num);
+ }
+ V(mutex);
+}
+
+const char *storage::print_list() {
+ P(mutex);
+
+ *list_str = 0;
+ STORE *store;
+ POOL_MEM tmp;
+ bool first = true;
+
+ foreach_alist(store, list) {
+ if (first) {
+ first = false;
+ } else {
+ pm_strcat(tmp.addr(), ", ");
+ }
+ pm_strcat(tmp.addr(), store->name());
+ }
+
+ V(mutex);
+ return quote_string(list_str, tmp.addr());
+}
+
+
+void LeastUsedStore::apply_policy(bool write_store) {
+ alist *store = write_store ? wstore.get_list() : rstore.get_list();
+ alist tmp_list(10, not_owned_by_alist);
+ uint32_t store_count = store->size();
+ uint32_t i, j, swap;
+ //TODO arrays below limit store list to 64 items currently...
+ uint32_t conc_arr[64];
+ uint32_t idx_arr[64];
+
+
+ for (uint32_t i=0; i<store_count; i++) {
+ tmp_list.append(store->get(i));
+ }
+
+ /* Reset list */
+ store->destroy();
+ store->init(10, not_owned_by_alist);
+
+ STORE *storage;
+ foreach_alist_index(i, storage, &tmp_list) {
+ idx_arr[i] = i;
+ conc_arr[i] = storage->getNumConcurrentJobs();
+ }
+
+ /* Simple bubble sort */
+ for (i = 0; i<store_count - 1; i++) {
+ for (j =0; j<store_count - i -1; j++) {
+ if (conc_arr[i] > conc_arr[i+1]) {
+ swap = conc_arr[i];
+ conc_arr[i] = conc_arr[i+1];
+ conc_arr[i+1] = swap;
+ swap = idx_arr[i];
+ idx_arr[i] = idx_arr[i+1];
+ idx_arr[i+1] = swap;
+ }
+ }
+ }
+
+ for (i=0; i<store_count; i++) {
+ storage = (STORE *)tmp_list.get(idx_arr[i]);
+ store->append(storage);
+ }
+}
+
+
+StorageManager::StorageManager() {
+ rstore.set_rw(false);
+ wstore.set_rw(true);
+};
+
+STORE *StorageManager::get_rstore() {
+ return rstore.get_store();
+}
+
+alist *StorageManager::get_rstore_list() {
+ return rstore.get_list();
+}
+
+const char *StorageManager::get_rsource() const {
+ return rstore.get_source();
+}
+
+const char *StorageManager::get_rmedia_type() const {
+ return rstore.get_media_type();
+}
+
+alist *StorageManager::get_wstore_list() {
+ return wstore.get_list();
+}
+
+const char *StorageManager::get_wsource() const {
+ return wstore.get_source();
+}
+
+const char *StorageManager::get_wmedia_type() const {
+ return wstore.get_media_type();
+}
+
+void StorageManager::set_rstore(STORE *storage, const char *source) {
+ rstore.set(storage, source);
+}
+
+void StorageManager::set_rstore(alist *storage, const char *source) {
+ rstore.set(storage, source);
+}
+
+void StorageManager::reset_rstorage() {
+ rstore.reset();
+}
+
+const char *StorageManager::print_rlist() {
+ return rstore.print_list();
+}
+
+bool StorageManager::set_current_wstorage(STORE *storage) {
+ return wstore.set_current_storage(storage);
+}
+
+void StorageManager::set_wstorage(STORE *storage, const char *source) {
+ wstore.set(storage, source);
+}
+
+void StorageManager::set_wstorage(alist *storage, const char *source) {
+ wstore.set(storage, source);
+}
+
+void StorageManager::reset_wstorage() {
+ wstore.reset();
+}
+
+const char *StorageManager::print_wlist() {
+ return wstore.print_list();
+}
+
+void StorageManager::reset_rwstorage() {
+ rstore.reset();
+ wstore.reset();
+}
+
+bool StorageManager::inc_read_stores(JCR *jcr) {
+ return rstore.inc_stores(jcr);
+}
+
+void StorageManager::dec_read_stores() {
+ return rstore.dec_stores();
+}
+
+bool StorageManager::inc_write_stores(JCR *jcr) {
+ return wstore.inc_stores(jcr);
+
+}
+
+void StorageManager::dec_write_stores() {
+ return wstore.dec_stores();
+}
--- /dev/null
+/*
+ Bacula(R) - The Network Backup Solution
+
+ Copyright (C) 2000-2020 Kern Sibbald
+
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
+
+ You may use this file and others of this release according to the
+ license defined in the LICENSE file, which includes the Affero General
+ Public License, v3.0 ("AGPLv3") and some additional permissions and
+ terms pursuant to its AGPLv3 Section 7.
+
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
+*/
+/*
+ * Storage manager classes.
+ * All of this code is intented to make managing
+ * (accessing, setting, incrementing counters, applying storage policy...) storage easier
+ * from the code perspective.
+ */
+
+#ifndef STORE_MNGR_H
+#define STORE_MNGR_H 1
+
+/* Forward delcaration */
+class STORE;
+
+/* Not so many policies for now...
+ * Some ideas for next ones:
+ * - Round robin
+ * - Most free space
+ * - Least CPU usage
+ * - Least network usage
+ * - A lot more
+ *
+ * Some protocol/interface changes will be needed to query all of the storages from
+ * the list about it's current status, depending of policy used.
+ */
+static char const *storage_mngmt_policy[] = {
+ "LeastUsed",
+ NULL
+};
+
+/*
+ * Helper class to make managing each storage type (write/read) easier.
+ * It contains storage resource ('store' member) which is currently used as well as list of all
+ * possible storage resource choices.
+ */
+class storage {
+ private:
+ bool write; /* Write or read storage */
+ STORE *store; /* Selected storage to be used */
+ alist *list; /* Storage possibilities */
+ POOLMEM *source; /* Where the storage came from */
+ POOLMEM *list_str; /* List of storage names in the list */
+ pthread_mutex_t mutex; /* Mutex for accessing items */
+
+ /* Only when we are a read storage - increment concurrent read counters for all storages on the list */
+ bool inc_rstores(JCR *jcr);
+
+ /* Only when we are a write storage - increment concurrent write counters for all storages on the list */
+ bool inc_wstores(JCR *jcr);
+ public:
+ storage();
+
+ ~storage();
+
+ /* Determine if we are write or read storage */
+ void set_rw(bool write);
+
+ /* Get storage which will be used next */
+ STORE *get_store() {
+ return store;
+ }
+
+ /* Get list of all possible storages */
+ alist *get_list();
+
+ /* Get source of the storage (pool, job, commandline, unknown, ...) */
+ const char *get_source() const;
+
+ /* Get media type of current storage */
+ const char *get_media_type() const;
+
+ /* Set storage override. Remove all previous storage.
+ * Can be called for single storage - list consists only one, specified storage then.
+ * Can be called for setting a list - internal list consists of same elemets as the list passed
+ * as an arg. First item from the list becames storage currently used.
+ */
+ void set(STORE *storage, const char *source);
+ void set(alist *storage, const char *source);
+
+ /* Reset class, remove all items from list, unset storage currently used, clean source */
+ void reset();
+
+ /* Set custom storage for next usage (it needs to be an item from the current store list) */
+ bool set_current_storage(STORE *storage);
+
+ /* Increment concurrent read/write counters for all storages on the list */
+ bool inc_stores(JCR *jcr);
+
+ /* Decrement concurrent read/write counters for all storages on the list */
+ void dec_stores();
+
+ /* Print all elements of the list (sample result of print_list() -> "File1, File2, File3" */
+ const char *print_list();
+};
+
+
+/*
+ * Storage Manager class responsible for managing all of the storage used by the JCR.
+ * It's holds read as well as write storage resources assigned to the JCR.
+ * It is a base class for Storage Policy (hence virtual 'apply_policy' method).
+ * Most of member functions are just wrappers around the storage class to make accessing
+ * and managin read/write storage in a bit more friendly way.
+ *
+ */
+class StorageManager : public SMARTALLOC {
+
+ protected:
+ storage rstore; /* Read storage */
+ storage wstore; /* Write storage */
+
+ public:
+ virtual void apply_policy(bool write_store) = 0;
+
+ virtual ~StorageManager() {
+ reset_rwstorage();
+ };
+
+ StorageManager();
+
+ /* Helper to validate if policy user wants to use is a valid one */
+ static bool check_policy(const char *policy) {
+ int i = 0;
+ while (storage_mngmt_policy[i]) {
+ if (strcmp(policy, storage_mngmt_policy[i]) == 0) {
+ return true;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ /************ READ STORAGE HELPERS ************/
+ STORE *get_rstore();
+
+ alist *get_rstore_list();
+
+ const char *get_rsource() const;
+
+ const char *get_rmedia_type() const;
+
+ void set_rstore(STORE *storage, const char *source);
+
+ void set_rstore(alist *storage, const char *source);
+
+ void reset_rstorage();
+
+ bool inc_read_stores(JCR *jcr);
+
+ void dec_read_stores();
+
+ const char *print_rlist();
+
+ /************ WRITE STORAGE HELPERS ************/
+ STORE *get_wstore() {
+ return wstore.get_store();
+ }
+
+ alist *get_wstore_list();
+
+ const char *get_wsource() const;
+
+ const char *get_wmedia_type() const;
+
+ bool set_current_wstorage(STORE *storage);
+
+ void set_wstorage(STORE *storage, const char *source);
+
+ void set_wstorage(alist *storage, const char *source);
+
+ void reset_wstorage();
+
+ const char *print_wlist();
+
+ bool inc_write_stores(JCR *jcr);
+
+ void dec_write_stores();
+
+ /************ GENERIC STORAGE HELPERS ************/
+ void reset_rwstorage();
+};
+
+/*
+ * Least used policy chooses storage from the list which has the least concurrent jobs number.
+ */
+class LeastUsedStore : public StorageManager {
+ public:
+ void apply_policy(bool write_store);
+
+ LeastUsedStore() {
+ }
+
+ ~LeastUsedStore() {
+ }
+};
+
+/*
+ * Default policy for the storage group. It uses first available storage from the list.
+ */
+class SimpleStoreMngr : public StorageManager {
+ private:
+
+ public:
+ void apply_policy(bool write_store) {
+ /* Do nothing for now */
+ }
+
+ SimpleStoreMngr() {
+ }
+
+ ~SimpleStoreMngr() {
+ }
+};
+
+#endif // STORE_MNGR_H
return false;
}
- if (ua->jcr->wstorage) {
- while (ua->jcr->wstorage->size()) {
- ua->jcr->wstorage->remove(0);
+ alist *wstorage = ua->jcr->store_mngr->get_wstore_list();
+ if (!wstorage->empty()) {
+ while (wstorage->size()) {
+ wstorage->remove(0);
}
}
MEDIA_DBR mr;
int num, i, max, startnum;
char name[MAX_NAME_LENGTH];
- STORE *store;
+ USTORE ustore;
int Slot = 0, InChanger = 0;
ua->send_msg(_(
}
/* Get media type */
- if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
- bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
+ if (get_storage_resource(ua, &ustore, false/*no default*/)) {
+ bstrncpy(mr.MediaType, ustore.store->media_type, sizeof(mr.MediaType));
} else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
return 1;
}
num = 1;
}
- if (store && store->autochanger) {
+ if (ustore.store && ustore.store->autochanger) {
if (!get_pint(ua, _("Enter slot (0 for none): "))) {
return 1;
}
mr.Slot = Slot++;
mr.InChanger = InChanger;
mr.Enabled = 1;
- set_storageid_in_mr(store, &mr);
+ set_storageid_in_mr(ustore.store, &mr);
Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
ua->error_msg("%s", db_strerror(ua->db));
char *options, char *tags)
{
BSOCK *sd;
- USTORE lstore;
- lstore.store = store;
- pm_strcpy(lstore.store_source, _("unknown source"));
- set_wstorage(ua->jcr, &lstore);
+ ua->jcr->store_mngr->set_wstorage(store, _("unknown source"));
/* Try connecting for up to 15 seconds */
ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
store->name(), store->address, store->SDport);
*/
static int setdebug_cmd(UAContext *ua, const char *cmd)
{
- STORE *store;
+ USTORE ustore;
CLIENT *client;
int64_t level=0, tags=0;
int trace_flag = -1;
if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
strcasecmp(ua->argk[i], NT_("sd")) == 0) {
- store = NULL;
if (ua->argv[i]) {
- store = GetStoreResWithName(ua->argv[i]);
- if (store) {
- do_storage_setdebug(ua, store, level, trace_flag,
+ ustore.store = GetStoreResWithName(ua->argv[i]);
+ if (ustore.store) {
+ do_storage_setdebug(ua, ustore.store, level, trace_flag,
hangup, blowup, options, tags_str);
return 1;
}
}
- store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
- if (store) {
- do_storage_setdebug(ua, store, level, trace_flag,
+ if (get_storage_resource(ua, &ustore, false/*no default*/, true/*unique*/)) {
+ do_storage_setdebug(ua, ustore.store, level, trace_flag,
hangup, blowup, options, tags_str);
return 1;
}
do_dir_setdebug(ua, level, trace_flag, options, tags_str);
break;
case 1:
- store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
- if (store) {
- do_storage_setdebug(ua, store, level, trace_flag, hangup, blowup,
+ if (get_storage_resource(ua, &ustore, false/*no default*/, true/*unique*/)) {
+ do_storage_setdebug(ua, ustore.store, level, trace_flag, hangup, blowup,
options, tags_str);
}
break;
static void do_storage_cmd(UAContext *ua, const char *command)
{
- USTORE store;
+ USTORE ustore;
BSOCK *sd;
JCR *jcr = ua->jcr;
char dev_name[MAX_NAME_LENGTH];
}
Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
- store.store = get_storage_resource(ua, true/*arg is storage*/);
- if (!store.store) {
+ if (!get_storage_resource(ua, &ustore, true/*arg is storage*/)) {
return;
}
- pm_strcpy(store.store_source, _("unknown source"));
- set_wstorage(jcr, &store);
- drive = get_storage_drive(ua, store.store);
+
+ jcr->store_mngr->set_wstorage(ustore.store, ustore.store_source);
+ drive = get_storage_drive(ua, ustore.store);
/* For the disable/enable/unmount commands, the slot is not mandatory */
if (strcasecmp(command, "disable") == 0 ||
strcasecmp(command, "enable") == 0 ||
strcasecmp(command, "unmount") == 0) {
slot = 0;
} else {
- slot = get_storage_slot(ua, store.store);
+ slot = get_storage_slot(ua, ustore.store);
}
/* Users may set a device name directly on the command line */
if ((i = find_arg_with_value(ua, "device")) > 0) {
bstrncpy(dev_name, ua->argv[i], sizeof(dev_name));
} else { /* We take the default device name */
- bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
+ bstrncpy(dev_name, ustore.store->dev_name(), sizeof(dev_name));
}
Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
- store.store->media_type, store.store->dev_name(), drive);
+ ustore.store->media_type, ustore.store->dev_name(), drive);
Dmsg4(120, "Cmd: %s %s drive=%d slot=%d\n", command, dev_name, drive, slot);
if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
/* Keep track of this important event */
ua->send_events("DC0013", EVENTS_TYPE_COMMAND, "%s storage=%s dev=%s",
- command, store.store->name(), dev_name);
+ command, ustore.store->name(), dev_name);
sd = jcr->store_bsock;
bash_spaces(dev_name);
bail_out:
close_db(ua);
close_sd_bsock(ua);
- ua->jcr->wstore = NULL;
+ ua->jcr->store_mngr->reset_wstorage();
if (results) {
free(results);
}
{
int drive = -1;
int64_t size, mtime;
- STORE *store = NULL;
+ USTORE ustore;
MEDIA_DBR mr;
POOL_DBR pr;
BSOCK *sd = NULL;
}
/* Choose storage */
- ua->jcr->wstore = store = get_storage_resource(ua, false);
- if (!store) {
+ if (!get_storage_resource(ua, &ustore, false)) {
goto bail_out;
}
- bstrncpy(storage, store->dev_name(), sizeof(storage));
- bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
+ ua->jcr->store_mngr->set_wstorage(ustore.store, ustore.store_source);
+ bstrncpy(storage, ustore.store->dev_name(), sizeof(storage));
+ bstrncpy(mr.MediaType, ustore.store->media_type, sizeof(mr.MediaType));
if ((sd=open_sd_bsock(ua)) == NULL) {
Dmsg0(100, "Can't open connection to SD\n");
bail_out:
close_db(ua);
close_sd_bsock(ua);
- ua->jcr->wstore = NULL;
+ ua->jcr->store_mngr->reset_wstorage();
return 1;
}
{
int i;
BSOCK *sd;
- USTORE lstore;
POOL_MEM buf;
if (!acl_access_ok(ua, Storage_ACL, store->name())) {
ua->error_msg(_("Restricted Client or Job does not permit access to Storage daemons\n"));
return;
}
- lstore.store = store;
- pm_strcpy(lstore.store_source, _("unknown source"));
- set_wstorage(ua->jcr, &lstore);
+
+ ua->jcr->store_mngr->set_wstorage(store, _("unknown source"));
/* Try connecting for up to 15 seconds */
if (!ua->api) ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
store->name(), store->address, store->SDport);
bool doall = true;
display_format_t format = COLLECT_SIMPLE;
char **margk;
- STORE *store = NULL;
+ USTORE ustore;
CLIENT *client = NULL;
Dmsg1(20, "cmd:%s:\n", cmd);
Dmsg0(20, "statistics format JSON\n");
continue;
}
- if (strcasecmp(ua->argk[i], "client") == 0 && store == NULL) {
+ if (strcasecmp(ua->argk[i], "client") == 0 && ustore.store == NULL) {
client = get_client_resource(ua, JT_BACKUP_RESTORE);
if (!client) {
goto bailout;
continue;
}
if (strcasecmp(ua->argk[i], "storage") == 0 && client == NULL) {
- store = get_storage_resource(ua, false /*no default*/, true/*unique*/);
- if (!store) {
+ if (!get_storage_resource(ua, &ustore, false /*no default*/, true/*unique*/)) {
goto bailout;
}
continue;
case 0: /* Director, the default behavior */
break;
case 1:
- store = select_storage_resource(ua, true/*unique*/);
- if (!store) {
+ ustore.store = select_storage_resource(ua, true/*unique*/);
+ if (!ustore.store) {
goto bailout;
}
break;
/* do collect client */
do_collect_client(ua, client, doall, format, margc, margk);
} else
- if (store){
+ if (ustore.store){
/* do collect storage */
- do_collect_storage(ua, store, doall, format, margc, margk);
+ do_collect_storage(ua, ustore.store, doall, format, margc, margk);
} else {
/* it is simpler to handle JSON array here */
if (format == COLLECT_JSON){
{
BSOCK *sd;
JCR *jcr = ua->jcr;
- USTORE lstore;
- lstore.store = store;
- pm_strcpy(lstore.store_source, _("unknown source"));
- set_wstorage(jcr, &lstore);
+ jcr->store_mngr->set_wstorage(store, _("unknown source"));
/* Try connecting for up to 15 seconds */
ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
store->name(), store->address, store->SDport);
static bool admin_cmds(UAContext *ua, const char *cmd)
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
- STORE *store=NULL;
+ USTORE ustore;
CLIENT *client=NULL;
bool dir=false;
bool do_deadlock=false;
if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
strcasecmp(ua->argk[i], NT_("sd")) == 0) {
- store = NULL;
if (ua->argv[i]) {
- store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
+ ustore.store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
}
- if (!store) {
- store = get_storage_resource(ua, false/*no default*/);
+ if (!ustore.store) {
+ get_storage_resource(ua, &ustore, false/*no default*/);
}
}
}
- if (!dir && !store && !client) {
+ if (!dir && !ustore.store && !client) {
/*
* We didn't find an appropriate keyword above, so
* prompt the user.
dir=true;
break;
case 1:
- store = get_storage_resource(ua, false/*no default*/);
+ get_storage_resource(ua, &ustore, false/*no default*/);
break;
case 2:
client = select_client_resource(ua, JT_BACKUP_RESTORE);
}
}
- if (store) {
- do_storage_cmd(ua, store, remote_cmd);
+ if (ustore.store) {
+ do_storage_cmd(ua, ustore.store, remote_cmd);
}
if (client) {
*/
void update_slots(UAContext *ua)
{
- USTORE store;
+ USTORE ustore;
vol_list_t *vl, *vol_list = NULL;
MEDIA_DBR mr;
char *slot_list;
if (!open_client_db(ua)) {
return;
}
- store.store = get_storage_resource(ua, true/*arg is storage*/);
- if (!store.store) {
+
+ if (!get_storage_resource(ua, &ustore, true/*arg is storage*/)) {
return;
}
- pm_strcpy(store.store_source, _("Command input"));
- set_wstorage(ua->jcr, &store);
- drive = get_storage_drive(ua, store.store);
+ ua->jcr->store_mngr->set_wstorage(ustore.store, ustore.store_source);
+ drive = get_storage_drive(ua, ustore.store);
scan = find_arg(ua, NT_("scan")) >= 0;
if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
} else {
mr.VolumeName[0] = 0;
}
- set_storageid_in_mr(store.store, &mr);
+ set_storageid_in_mr(ustore.store, &mr);
Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
db_lock(ua->db);
Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
/* If Slot, Inchanger, and StorageId have changed, update the Media record */
- if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
+ if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != ustore.store->StorageId) {
mr.Slot = vl->Slot;
mr.InChanger = 1;
if (have_enabled) {
mr.Enabled = Enabled;
}
- set_storageid_in_mr(store.store, &mr);
+ set_storageid_in_mr(ustore.store, &mr);
if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
ua->error_msg("%s", db_strerror(ua->db));
} else {
}
mr.clear();
mr.InChanger = 1;
- set_storageid_in_mr(store.store, &mr);
+ set_storageid_in_mr(ustore.store, &mr);
db_lock(ua->db);
for (int i=1; i <= max_slots; i++) {
if (slot_list[i]) {
*/
static int do_label(UAContext *ua, const char *cmd, int relabel)
{
- USTORE store;
+ USTORE ustore;
BSOCK *sd;
char dev_name[MAX_NAME_LENGTH];
MEDIA_DBR mr, omr;
label_barcodes = true;
}
- store.store = get_storage_resource(ua, true/*use default*/);
- if (!store.store) {
+ if (!get_storage_resource(ua, &ustore, true/*use default*/)) {
return 1;
}
- pm_strcpy(store.store_source, _("Command input"));
- set_wstorage(ua->jcr, &store);
- drive = get_storage_drive(ua, store.store);
+ ua->jcr->store_mngr->set_wstorage(ustore.store, ustore.store_source);
+ drive = get_storage_drive(ua, ustore.store);
if (label_barcodes) {
label_from_barcodes(ua, drive);
mr.Slot = 0;
}
mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
- } else if (store.store->autochanger) {
+ } else if (ustore.store->autochanger) {
if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
return 1;
}
}
mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
}
- set_storageid_in_mr(store.store, &mr);
+ set_storageid_in_mr(ustore.store, &mr);
- bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
+ bstrncpy(mr.MediaType, ustore.store->media_type, sizeof(mr.MediaType));
/* Must select Pool if not already done */
if (pr.PoolId == 0) {
}
}
if (ua->automount) {
- bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
+ bstrncpy(dev_name, ustore.store->dev_name(), sizeof(dev_name));
ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
bash_spaces(dev_name);
sd->fsend("mount %s drive=%d slot=%d", dev_name, drive, mr.Slot);
*/
static void label_from_barcodes(UAContext *ua, int drive)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
POOL_DBR pr;
MEDIA_DBR mr, omr;
vol_list_t *vl, *vol_list = NULL;
uint64_t VolBytes = 0;
uint64_t VolABytes = 0;
uint32_t VolType = 0;
+ STORE *wstore = ua->jcr->store_mngr->get_wstore();
if (!(sd=open_sd_bsock(ua))) {
return false;
}
- bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
+ bstrncpy(dev_name, wstore->dev_name(), sizeof(dev_name));
bash_spaces(dev_name);
bash_spaces(mr->VolumeName);
bash_spaces(mr->MediaType);
mr->VolABytes = VolABytes;
mr->VolType = VolType;
mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */
- set_storageid_in_mr(ua->jcr->wstore, mr);
+ set_storageid_in_mr(wstore, mr);
if (!db_update_media_record(ua->jcr, ua->db, mr)) {
ua->error_msg("%s", db_strerror(ua->db));
ok = false;
mr->VolType = VolType;
mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */
mr->Enabled = 1;
- set_storageid_in_mr(ua->jcr->wstore, mr);
+ set_storageid_in_mr(wstore, mr);
if (db_create_media_record(ua->jcr, ua->db, mr)) {
ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
mr->VolumeName, mr->Slot);
static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
BSOCK *sd;
char dev_name[MAX_NAME_LENGTH];
char *VolName = NULL;
*/
static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
char dev_name[MAX_NAME_LENGTH];
BSOCK *sd;
vol_list_t *vl;
*/
static int get_num_slots_from_SD(UAContext *ua)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
char dev_name[MAX_NAME_LENGTH];
BSOCK *sd;
int slots = 0;
*/
int get_num_drives_from_SD(UAContext *ua)
{
- STORE *store = ua->jcr->wstore;
+ STORE *store = ua->jcr->store_mngr->get_wstore();
char dev_name[MAX_NAME_LENGTH];
BSOCK *sd;
int drives = 0;
*/
void status_slots(UAContext *ua, STORE *store_r)
{
- USTORE store;
+ STORE *store;
POOL_DBR pr;
vol_list_t *vl, *vol_list = NULL;
MEDIA_DBR mr;
if (!open_client_db(ua)) {
return;
}
- store.store = store_r;
+ store = store_r;
- pm_strcpy(store.store_source, _("Command input"));
- set_wstorage(ua->jcr, &store);
- get_storage_drive(ua, store.store);
+ ua->jcr->store_mngr->set_wstorage(store, _("Command input"));
+ get_storage_drive(ua, store);
max_slots = get_num_slots_from_SD(ua);
bail_out:
close_db(ua);
close_sd_bsock(ua);
- ua->jcr->wstore = NULL;
+ ua->jcr->store_mngr->reset_wstorage();
if (results) {
free(results);
}
void find_storage_resource(UAContext *ua, RESTORE_CTX &rx, char *Storage, char *MediaType)
{
STORE *store;
+ USTORE ustore;
if (rx.store) {
Dmsg1(200, "Already have store=%s\n", rx.store->name());
}
/* Take command line arg, or ask user if none */
- rx.store = get_storage_resource(ua, false /* don't use default */);
- if (rx.store) {
- Dmsg1(200, "Set store=%s\n", rx.store->name());
+
+ if (get_storage_resource(ua, &ustore, false /* don't use default */)) {
+ Dmsg2(200, "Set store=%s store source=%s\n", ustore.store->name(), ustore.store_source);
}
+ rx.store = ustore.store;
}
/*
* Fill in storage data according to what is setup
* in the run context, and make sure the user
- * has authorized access to it.
+ * has authorized access to it. If no storage is found, list from job/pool is used later (see set_jcr_default_store()).
*/
static bool get_storage(UAContext *ua, run_ctx &rc)
-{
- if (rc.store_name) {
- rc.store->store = GetStoreResWithName(rc.store_name);
- pm_strcpy(rc.store->store_source, _("Command input"));
- if (!rc.store->store) {
- if (*rc.store_name != 0) {
- ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
- }
- rc.store->store = select_storage_resource(ua);
- pm_strcpy(rc.store->store_source, _("user selection"));
- }
- } else if (!rc.store->store) {
- get_job_storage(rc.store, rc.job, NULL); /* use default */
- }
- if (!rc.store->store) {
- ua->error_msg(_("No storage specified.\n"));
- return false;
- } else if (!acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
- ua->error_msg(_("No authorization. Storage \"%s\".\n"),
- rc.store->store->name());
- return false;
- }
- Dmsg1(800, "Using storage=%s\n", rc.store->store->name());
- return true;
-}
-
-static bool get_storage_from_job_record(UAContext *ua, run_ctx &rc)
{
if (rc.restart) {
char name[MAX_NAME_LENGTH];
Dmsg1(50, "Found Storage resource related to the JobId=%ld\n",
rc.JobId);
return true;
- }
+ } else {
Dmsg1(50, "Could not find any Storage resource related to the one refered by JobId=%ld\n",
rc.JobId);
+ }
} else {
Dmsg1(50, "Could not find any Storage record in catalog related to the one refered by JobId=%ld\n",
rc.JobId);
}
+ } else if (rc.store_name) {
+ rc.store->store = GetStoreResWithName(rc.store_name);
+ pm_strcpy(rc.store->store_source, _("Command input"));
+ if (!rc.store->store) {
+ if (*rc.store_name != 0) {
+ ua->warning_msg(_("Storage \"%s\" not found.\n"), rc.store_name);
+ }
+ rc.store->store = select_storage_resource(ua);
+ pm_strcpy(rc.store->store_source, _("user selection"));
+ }
+ }
+
+ if (!rc.store->store) {
+ get_job_storage(rc.store, rc.job, NULL); /* use default */
}
- get_job_storage(rc.store, rc.job, NULL);
+ if (rc.store->store && !acl_access_ok(ua, Storage_ACL, rc.store->store->name())) {
+ ua->error_msg(_("No authorization. Storage \"%s\".\n"),
+ rc.store->store->name());
+ return false;
+ }
+
return true;
}
return false;
}
- get_storage_from_job_record(ua, rc);
-
bmemset(&fr, 0, sizeof(fr));
fr.FileSetId = rc.jr.FileSetId;
if (!db_get_fileset_record(ua->jcr, ua->db, &fr)) {
{
char ec1[30], edl[50];
char dt[MAX_TIME_LENGTH];
+ STORE *wstore = jcr->store_mngr->get_wstore();
Dmsg1(800, "JobType=%c\n", jcr->getJobType());
+ STORE *rstore = jcr->store_mngr->get_rstore();
switch (jcr->getJobType()) {
case JT_ADMIN:
if (ua->api) {
job->name(),
jcr->fileset->name(),
NPRT(jcr->client->name()),
- jcr->wstore?jcr->wstore->name():"*None*",
+ wstore?wstore->name():"*None*",
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->JobPriority);
} else {
job->name(),
jcr->fileset->name(),
NPRT(jcr->client->name()),
- jcr->wstore?jcr->wstore->name():"*None*",
+ wstore?wstore->name():"*None*",
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->JobPriority);
}
jcr->fileset->name(),
NPRT(jcr->pool->name()),
next_pool,
- jcr->wstore?jcr->wstore->name():"*None*",
+ wstore?wstore->name():"*None*",
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->JobPriority,
jcr->plugin_options?"Plugin Options: ":"",
jcr->fileset->name(),
NPRT(jcr->pool->name()), jcr->pool_source,
next_pool,
- jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
+ wstore?wstore->name():"*None*", jcr->store_mngr->get_wsource(),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->JobPriority,
jcr->plugin_options?"Plugin Options: ":"",
jcr->client->name(),
jcr->fileset->name(),
NPRT(jcr->pool->name()), jcr->pool_source,
- jcr->rstore->name(), jcr->rstore_source,
+ rstore->name(), jcr->store_mngr->get_rsource(),
Name,
verify_list,
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->client->name(),
jcr->fileset->name(),
NPRT(jcr->pool->name()), jcr->pool_source,
- jcr->rstore->name(), jcr->rstore_source,
+ rstore->name(), jcr->store_mngr->get_rsource(),
Name,
verify_list,
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->fileset->name(),
client_name,
jcr->client->name(),
- jcr->rstore->name(),
+ rstore->name(),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
jcr->JobPriority,
jcr->fileset->name(),
client_name,
jcr->client->name(),
- jcr->rstore->name(),
+ rstore->name(),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
jcr->JobPriority,
jcr->fileset->name(),
client_name,
jcr->client->name(),
- jcr->rstore->name(),
+ rstore->name(),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
jcr->JobPriority,
jcr->fileset->name(),
client_name,
jcr->client->name(),
- jcr->rstore->name(),
+ rstore->name(),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
jcr->JobPriority,
"Plugin Options: %s\n"),
replace,
jcr->client->name(),
- jcr->rstore->name(),
+ rstore->name(),
jcr->RestoreJobId==0?"*None*":edit_uint64(jcr->RestoreJobId, ec1),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
jcr->fileset->name(),
NPRT(jcr->pool->name()),
jcr->next_pool?jcr->next_pool->name():"*None*",
- jcr->rstore->name(),
- jcr->wstore?jcr->wstore->name():"*None*",
+ rstore->name(),
+ wstore?wstore->name():"*None*",
jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
NPRT(jcr->pool->name()), jcr->pool_source,
jcr->next_pool?jcr->next_pool->name():"*None*",
NPRT(jcr->next_pool_source),
- jcr->rstore->name(), jcr->rstore_source,
- jcr->wstore?jcr->wstore->name():"*None*", jcr->wstore_source,
+ rstore->name(), jcr->store_mngr->get_rsource(),
+ wstore?wstore->name():"*None*", jcr->store_mngr->get_wsource(),
jcr->MigrateJobId==0?"*None*":edit_uint64(jcr->MigrateJobId, ec1),
bstrutime(dt, sizeof(dt), jcr->sched_time),
jcr->catalog->name(),
* If use_default is set, we assume that any keyword without a value
* is the name of the Storage resource wanted.
*/
-STORE *get_storage_resource(UAContext *ua, bool use_default, bool unique)
+bool get_storage_resource(UAContext *ua, USTORE *ustore, bool use_default, bool unique)
{
char store_name[MAX_NAME_LENGTH];
- STORE *store = NULL;
int jobid;
JCR *jcr;
int i;
char ed1[50];
+
*store_name = 0;
+ ustore->store = NULL;
for (i=1; i<ua->argc; i++) {
if (use_default && !ua->argv[i]) {
/* Default argument is storage (except in enable/disable command) */
if (store_name[0]) {
ua->error_msg(_("Storage name given twice.\n"));
- return NULL;
+ goto bail_out;
}
bstrncpy(store_name, ua->argk[i], sizeof(store_name));
if (store_name[0] == '?') {
*store_name = 0;
break;
}
+
+ pm_strcpy(ustore->store_source, _("Command line"));
} else {
if (strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
strcasecmp(ua->argk[i], NT_("sd")) == 0) {
bstrncpy(store_name, NPRTB(ua->argv[i]), sizeof(store_name));
+ pm_strcpy(ustore->store_source, _("Command line (storage parameter)"));
} else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
jobid = str_to_int64(ua->argv[i]);
if (jobid <= 0) {
ua->error_msg(_("Expecting jobid=nn command, got: %s\n"), ua->argk[i]);
- return NULL;
+ goto bail_out;
}
if (!(jcr=get_jcr_by_id(jobid))) {
ua->error_msg(_("JobId %s is not running.\n"), edit_int64(jobid, ed1));
- return NULL;
+ goto bail_out;
}
- if (jcr->wstore) {
- bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
+ STORE *wstore = jcr->store_mngr->get_wstore();
+ if (wstore) {
+ bstrncpy(store_name, wstore->name(), sizeof(store_name));
+ pm_strcpy(ustore->store_source, _("Command line (jobid parameter)"));
}
free_jcr(jcr);
strcasecmp(ua->argk[i], NT_("jobname")) == 0) {
if (!ua->argv[i]) {
ua->error_msg(_("Expecting job=xxx, got: %s.\n"), ua->argk[i]);
- return NULL;
+ goto bail_out;
}
if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
ua->error_msg(_("Job \"%s\" is not running.\n"), ua->argv[i]);
- return NULL;
+ goto bail_out;
}
- if (jcr->wstore) {
- bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
+ STORE *wstore = jcr->store_mngr->get_wstore();
+ if (wstore) {
+ bstrncpy(store_name, wstore->name(), sizeof(store_name));
+ pm_strcpy(ustore->store_source, _("Command line (job/jobname parameter)"));
}
free_jcr(jcr);
} else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
if (!ua->argv[i]) {
ua->error_msg(_("Expecting ujobid=xxx, got: %s.\n"), ua->argk[i]);
- return NULL;
+ goto bail_out;
}
if ((jcr=get_jcr_by_full_name(ua->argv[i]))) {
- if (jcr->wstore) {
- bstrncpy(store_name, jcr->wstore->name(), sizeof(store_name));
+ STORE *wstore = jcr->store_mngr->get_wstore();
+ if (wstore) {
+ bstrncpy(store_name, wstore->name(), sizeof(store_name));
+ pm_strcpy(ustore->store_source, _("Command line (ujobid parameter)"));
}
free_jcr(jcr);
}
}
if (store_name[0] != 0) {
- store = (STORE *)GetResWithName(R_STORAGE, store_name);
- if (!store && strcmp(store_name, "storage") != 0) {
+ ustore->store = (STORE *)GetResWithName(R_STORAGE, store_name);
+ if (!ustore->store && strcmp(store_name, "storage") != 0) {
/* Looks that the first keyword of the line was not a storage name, make
* sure that it's not "storage=" before we print the following message
*/
ua->error_msg(_("Storage resource \"%s\": not found\n"), store_name);
}
}
- if (store && !acl_access_ok(ua, Storage_ACL, store->name())) {
- store = NULL;
+ if (ustore->store && !acl_access_ok(ua, Storage_ACL, ustore->store->name())) {
+ ustore->store = NULL;
}
/* No keywords found, so present a selection list */
- if (!store) {
- store = select_storage_resource(ua, unique);
+ if (!ustore->store) {
+ ustore->store = select_storage_resource(ua, unique);
+ pm_strcpy(ustore->store_source, _("User selection"));
}
- return store;
+
+bail_out:
+ return ustore->store != NULL;
}
/* Get drive that we are working with for this storage */
uint32_t **results) /* List of MediaId */
{
bool allpools=false, has_vol = false;;
- STORE *store;
+ USTORE ustore;
*nb = 0;
*results = NULL;
if (storage) {
/* Choose storage */
- ua->jcr->wstore = store = get_storage_resource(ua, false);
- if (!store) {
+ if (!get_storage_resource(ua, &ustore, false)) {
goto bail_out;
}
- bstrncpy(storage, store->dev_name(), MAX_NAME_LENGTH);
- set_storageid_in_mr(store, mr);
+ ua->jcr->store_mngr->set_wstorage(ustore.store, ustore.store_source);
+ bstrncpy(storage, ustore.store->dev_name(), MAX_NAME_LENGTH);
+ set_storageid_in_mr(ustore.store, mr);
}
if (!open_db(ua)) {
}
close_db(ua);
- ua->jcr->wstore = NULL;
+ ua->jcr->store_mngr->reset_wstorage();
if (*results) {
free(*results);
*results = NULL;
bool dot_status_cmd(UAContext *ua, const char *cmd)
{
- STORE *store;
+ USTORE ustore;
CLIENT *client;
JCR* njcr = NULL;
s_last_job* job;
do_client_status(ua, client, ua->argk[2]);
}
} else if (strcasecmp(ua->argk[1], "storage") == 0) {
- store = get_storage_resource(ua, false /*no default*/, true/*unique*/);
- if (!store) {
+ if (!get_storage_resource(ua, &ustore, false /*no default*/, true/*unique*/)) {
ua->send_msg("1900 Bad .status command, wrong argument.\n");
return false;
}
- do_storage_status(ua, store, ua->argk[2]);
+ do_storage_status(ua, ustore.store, ua->argk[2]);
} else {
ua->send_msg("1900 Bad .status command, wrong argument.\n");
return false;
static int do_network_status(UAContext *ua)
{
CLIENT *client = NULL;
- USTORE store;
+ USTORE ustore;
JCR *jcr = ua->jcr;
char *store_address, ed1[50];
uint32_t store_port;
return 1;
}
- store.store = get_storage_resource(ua, false, true);
- if (!store.store) {
+ if (!get_storage_resource(ua, &ustore, false, true)) {
return 1;
}
jcr->client = client;
- set_wstorage(jcr, &store);
+ jcr->store_mngr->set_wstorage(ustore.store, NULL);
if (!ua->api) {
ua->send_msg(_("Connecting to Storage %s at %s:%d\n"),
- store.store->name(), store.store->address, store.store->SDport);
+ ustore.store->name(), ustore.store->address, ustore.store->SDport);
}
if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
goto bail_out;
}
- if (!start_storage_daemon_job(jcr, NULL, NULL)) {
+ if (!start_storage_daemon_job(jcr, NULL, NULL, true /* wait */ )) {
goto bail_out;
}
goto bail_out;
}
- store_address = store.store->address; /* dummy */
+ store_address = ustore.store->address; /* dummy */
store_port = 0; /* flag that SD calls FD */
} else {
* then wait for File daemon to make connection
* with Storage daemon.
*/
- if (store.store->SDDport == 0) {
- store.store->SDDport = store.store->SDport;
+ if (ustore.store->SDDport == 0) {
+ ustore.store->SDDport = ustore.store->SDport;
}
- store_address = get_storage_address(jcr->client, store.store);
- store_port = store.store->SDDport;
+ store_address = get_storage_address(jcr->client, ustore.store);
+ store_port = ustore.store->SDDport;
}
- if (!send_store_addr_to_fd(jcr, store.store, store_address, store_port)) {
+ if (!send_store_addr_to_fd(jcr, ustore.store, store_address, store_port)) {
goto bail_out;
}
if (!ua->api) {
ua->info_msg(_("Running network test between Client=%s and Storage=%s with %sB ...\n"),
- client->name(), store.store->name(), edit_uint64_with_suffix(nb, ed1));
+ client->name(), ustore.store->name(), edit_uint64_with_suffix(nb, ed1));
}
if (!jcr->file_bsock->fsend("testnetwork bytes=%llu rtt=%llu\n", nb, nbrtt)) {
free_bsock(jcr->store_bsock);
jcr->client = NULL;
- free_wstorage(jcr);
+ jcr->store_mngr->reset_wstorage(); /* we don't read so release */
return 1;
}
*/
int status_cmd(UAContext *ua, const char *cmd)
{
- STORE *store;
+ USTORE ustore;
CLIENT *client;
int item, i;
}
return 1;
} else {
- store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
- if (store) {
+ if (get_storage_resource(ua, &ustore, false/*no default*/, true/*unique*/)) {
if (find_arg(ua, NT_("slots")) > 0) {
- status_slots(ua, store);
+ status_slots(ua, ustore.store);
} else {
- do_storage_status(ua, store, NULL);
+ do_storage_status(ua, ustore.store, NULL);
}
}
return 1;
do_director_status(ua);
break;
case 1:
- store = select_storage_resource(ua, true/*unique*/);
- if (store) {
- do_storage_status(ua, store, NULL);
+ ustore.store = select_storage_resource(ua, true/*unique*/);
+ if (ustore.store) {
+ do_storage_status(ua, ustore.store, NULL);
}
break;
case 2:
static void do_storage_status(UAContext *ua, STORE *store, char *cmd)
{
BSOCK *sd;
- USTORE lstore;
int i;
if (!acl_access_ok(ua, Storage_ACL, store->name())) {
ua->error_msg(_("Restricted Client or Job does not permit access to Storage daemons\n"));
return;
}
- lstore.store = store;
- pm_strcpy(lstore.store_source, _("unknown source"));
- set_wstorage(ua->jcr, &lstore);
+ ua->jcr->store_mngr->set_wstorage(store, _("unknown source"));
/* Try connecting for up to 15 seconds */
if (!ua->api) ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
store->name(), store->address, store->SDport);
}
if (ok) {
mr.PoolId = jcr->jr.PoolId;
- jcr->wstore = sp->store;
- set_storageid_in_mr(jcr->wstore, &mr);
+ jcr->store_mngr->set_wstorage(sp->store, "PRT runtime");
+ set_storageid_in_mr(jcr->store_mngr->get_wstore(), &mr);
Dmsg0(250, "call find_next_volume_for_append\n");
/* no need to set ScratchPoolId, since we use fnv_no_create_vol */
ok = find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_no_prune, errmsg);
} else if (ua->api > 1) {
POOL *p = jcr->pool;
- STORE *s = jcr->wstore;
+ STORE *s = jcr->store_mngr->get_wstore();
ua->send_msg("%s",
ow->get_output(OT_CLEAR,
OT_START_OBJ,
}
}
status = jcr->JobStatus;
+ STORE *rstore = jcr->store_mngr->get_rstore();
+ STORE *wstore = jcr->store_mngr->get_wstore();
switch (status) {
case JS_Created:
msg = _("is waiting execution");
break;
case JS_WaitSD:
emsg = (char *) get_pool_memory(PM_FNAME);
- if (jcr->wstore) {
- Mmsg(emsg, _("is waiting on Storage \"%s\""), jcr->wstore->name());
- } else if (jcr->rstore) {
- Mmsg(emsg, _("is waiting on Storage \"%s\""), jcr->rstore->name());
+ if (wstore) {
+ Mmsg(emsg, _("is waiting on Storage \"%s\""), wstore->name());
+ } else if (rstore) {
+ Mmsg(emsg, _("is waiting on Storage \"%s\""), rstore->name());
} else {
Mmsg(emsg, _("is waiting on Storage"));
}
emsg = (char *)get_pool_memory(PM_FNAME);
pool_mem = true;
}
- if (!jcr->client || !jcr->wstore) {
+ if (!jcr->client || !wstore) {
Mmsg(emsg, _("is waiting for Client to connect to Storage daemon"));
} else {
Mmsg(emsg, _("is waiting for Client %s to connect to Storage %s"),
- jcr->client->name(), jcr->wstore->name());
+ jcr->client->name(), wstore->name());
}
msg = emsg;
}
} else if (ua->api > 1) {
CLIENT *c = jcr->client;
FILESET *f = jcr->fileset;
- STORE *w = jcr->wstore;
- STORE *r = jcr->rstore;
+ STORE *w = wstore;
+ STORE *r = rstore;
JOB *j = jcr->job;
ua->send_msg("%s", ow.get_output(OT_CLEAR,
OT_START_OBJ,
pm_strcpy(jcr->rpool_source, jcr->pool_source);
/* If pool storage specified, use it for virtual full */
- copy_rstorage(jcr, jcr->pool->storage, _("Pool resource"));
+ jcr->store_mngr->set_rstore(jcr->pool->storage, _("Pool resource"));
Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
db_list_ctx jobids;
UAContext *ua;
- Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
+ Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->store_mngr->get_rstore_list(), jcr->store_mngr->get_wstore_list());
Dmsg2(100, "Read store=%s, write store=%s\n",
- ((STORE *)jcr->rstorage->first())->name(),
- ((STORE *)jcr->wstorage->first())->name());
+ ((STORE *)jcr->store_mngr->get_rstore_list()->first())->name(),
+ ((STORE *)jcr->store_mngr->get_wstore_list()->first())->name());
jcr->wasVirtualFull = true; /* remember where we came from */
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage, /*send_bsr*/true)) {
+ if (!start_storage_daemon_job(jcr, jcr->store_mngr->get_rstore_list(), jcr->store_mngr->get_wstore_list(), /*send_bsr*/true)) {
return false;
}
Dmsg0(100, "Storage daemon connection OK\n");
double kbps, compression;
utime_t RunTime;
POOL_MEM query(PM_MESSAGE);
+ STORE *wstore = jcr->store_mngr->get_wstore();
Dmsg2(100, "Enter vbackup_cleanup %d %c\n", TermCode, TermCode);
memset(&cr, 0, sizeof(cr));
jcr->fileset->name(), jcr->FSCreateTime,
jcr->pool->name(), jcr->pool_source,
jcr->catalog->name(), jcr->catalog_source,
- jcr->wstore->name(), jcr->wstore_source,
+ wstore->name(), jcr->store_mngr->get_wsource(),
schedt,
sdt,
edt,
case L_VERIFY_INIT:
case L_VERIFY_CATALOG:
case L_VERIFY_DISK_TO_CATALOG:
- free_rstorage(jcr);
- free_wstorage(jcr);
+ jcr->store_mngr->reset_rwstorage();
break;
case L_VERIFY_DATA:
case L_VERIFY_VOLUME_TO_CATALOG:
- free_wstorage(jcr);
+ jcr->store_mngr->reset_wstorage();
break;
default:
Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->getJobLevel(),
char *store_address;
uint32_t store_port;
const char *Name;
+ STORE *rstore = jcr->store_mngr->get_rstore();
- free_wstorage(jcr); /* we don't write */
+ jcr->store_mngr->reset_wstorage();
memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) {
+ if (!start_storage_daemon_job(jcr, jcr->store_mngr->get_rstore_list(), NULL, true /* wait */)) {
return false;
}
sd = jcr->store_bsock;
if (!run_storage_and_start_message_thread(jcr, jcr->store_bsock)) {
return false;
}
- store_address = jcr->rstore->address; /* dummy */
+ store_address = rstore->address; /* dummy */
store_port = 0; /* flag that SD calls FD */
} else {
/*
* send Storage daemon address to the File daemon
*/
- if (jcr->rstore->SDDport == 0) {
- jcr->rstore->SDDport = jcr->rstore->SDport;
+ if (rstore->SDDport == 0) {
+ rstore->SDDport = rstore->SDport;
}
- store_address = get_storage_address(jcr->client, jcr->rstore);
- store_port = jcr->rstore->SDDport;
+ store_address = get_storage_address(jcr->client, rstore);
+ store_port = rstore->SDDport;
}
- if (!send_store_addr_to_fd(jcr, jcr->rstore, store_address, store_port)) {
+ if (!send_store_addr_to_fd(jcr, rstore, store_address, store_port)) {
goto bail_out;
}
JOB *job; /* Job resource */
JOB *verify_job; /* Job resource of verify previous job */
alist *plugin_config; /* List of ConfigFile needed for restore */
- alist *rstorage; /* Read storage possibilities */
- STORE *rstore; /* Selected read storage */
- alist *wstorage; /* Write storage possibilities */
- STORE *wstore; /* Selected write storage */
+ StorageManager *store_mngr;
CLIENT *client; /* Client resource */
POOL *pool; /* Pool resource = write for migration */
POOL *next_pool; /* Next pool override */
POOLMEM *pool_source; /* Where pool came from */
POOLMEM *next_pool_source; /* Where next pool came from */
POOLMEM *rpool_source; /* Where migrate read pool came from */
- POOLMEM *rstore_source; /* Where read storage came from */
- POOLMEM *wstore_source; /* Where write storage came from */
POOLMEM *catalog_source; /* Where catalog came from */
POOLMEM *next_vol_list; /* Volumes previously requested */
rblist *bsr_list; /* Bootstrap that can be needed during restore */
/* Requests from the Director daemon */
static char use_storage[] = "use storage=%127s media_type=%127s "
- "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d\n";
+ "pool_name=%127s pool_type=%127s append=%d copy=%d stripe=%d wait=%d\n";
static char use_device[] = "use device=%127s\n";
/* Responses sent to Director daemon */
BSOCK *dir = jcr->dir_bsock;
int32_t append;
bool ok;
- int32_t Copy, Stripe;
+ int32_t Copy, Stripe, Wait;
DIRSTORE *store;
RCTX rctx;
alist *dirstore;
Dmsg1(dbglvl, "<dird: %s", dir->msg);
ok = sscanf(dir->msg, use_storage, store_name.c_str(),
media_type.c_str(), pool_name.c_str(),
- pool_type.c_str(), &append, &Copy, &Stripe) == 7;
+ pool_type.c_str(), &append, &Copy, &Stripe, &Wait) == 8;
if (!ok) {
break;
}
if (ok) {
break;
}
+ if (!Wait) {
+ /* Director does some kind of 'quick round' now, does not want to wait for device to become available.
+ * If none of the devices is ready now, director will probably do a second use_device call,
+ * this time with 'wait' set to 1 */
+ break;
+ }
+
/* Keep reservations locked *except* during wait_for_device() */
unlock_reservations();
/*
* means nothing configured. If a device is suitable but busy
* with another Volume, we will not come here.
*/
- unbash_spaces(dir->msg);
- pm_strcpy(jcr->errmsg, dir->msg);
- Jmsg(jcr, M_FATAL, 0, _("Device reservation failed for JobId=%d: %s\n"),
- jcr->JobId, jcr->errmsg);
dir->fsend(NO_device, dev_name.c_str());
-
Dmsg1(dbglvl, ">dird: %s", dir->msg);
}
} else {