Skip to content
Permalink
Browse files

Merge pull request #160 from bareos/dev/arogge/master/fix-1056

dird: redesign GetNdmpEnvironmentString() API
  • Loading branch information...
arogge committed Mar 27, 2019
2 parents fa885c2 + 2b78532 commit 020ca8e3d05f33e19d3f423833348f19050d7b8c
@@ -47,6 +47,8 @@

#define faddr_t long

struct VolumeSessionInfo;

/**
* Generic definitions of list types, list handlers and result handlers.
*/
@@ -821,12 +823,18 @@ class BareosDb
int GetNdmpLevelMapping(JobControlRecord* jcr,
JobDbRecord* jr,
char* filesystem);
bool GetNdmpEnvironmentString(JobControlRecord* jcr,
JobDbRecord* jr,
bool GetNdmpEnvironmentString(const std::string& query,
DB_RESULT_HANDLER* ResultHandler,
void* ctx);
bool GetNdmpEnvironmentString(const VolumeSessionInfo& vsi,
int32_t FileIndex,
DB_RESULT_HANDLER* ResultHandler,
void* ctx);
bool GetNdmpEnvironmentString(JobId_t JobId,
DB_RESULT_HANDLER* ResultHandler,
void* ctx);
bool GetNdmpEnvironmentString(JobControlRecord* jcr,
JobId_t JobId,
bool GetNdmpEnvironmentString(JobId_t JobId,
int32_t FileIndex,
DB_RESULT_HANDLER* ResultHandler,
void* ctx);
bool PrepareMediaSqlQuery(JobControlRecord* jcr,
@@ -1322,6 +1322,8 @@ bool BareosDb::CreateNdmpEnvironmentString(JobControlRecord* jcr,
char esc_envname[MAX_ESCAPE_NAME_LENGTH];
char esc_envvalue[MAX_ESCAPE_NAME_LENGTH];

Jmsg(jcr, M_INFO, 0, "NDMP Environment: %s=%s\n", name, value);

DbLock(this);

EscapeString(jcr, esc_envname, name, strlen(name));
@@ -39,6 +39,8 @@
#include "cats.h"
#include "sql.h"
#include "lib/edit.h"
#include "lib/volume_session_info.h"
#include "include/make_unique.h"

/* -----------------------------------------------------------------------
*
@@ -1709,34 +1711,80 @@ int BareosDb::GetNdmpLevelMapping(JobControlRecord* jcr,
return dumplevel;
}

/**
* CountingHandler() with a CountContext* can be used to count the number of
* times that SqlQueryWithHandler() calls the handler.
* This is not neccesarily the number of rows, because the ResultHandler can
* stop processing of further rows by returning non-zero.
*/
struct CountContext {
DB_RESULT_HANDLER* handler;
void* ctx;
int count;

CountContext(DB_RESULT_HANDLER* t_handler, void* t_ctx)
: handler(t_handler), ctx(t_ctx), count(0)
{
}
};

static int CountingHandler(void* counting_ctx, int num_fields, char** rows)
{
auto* c = static_cast<struct CountContext*>(counting_ctx);
c->count++;
return c->handler(c->ctx, num_fields, rows);
}

/**
* Fetch NDMP Job Environment based on raw SQL query.
* Returns false: on sql failure or when 0 rows were returned
* true: otherwise
*/
bool BareosDb::GetNdmpEnvironmentString(const std::string& query,
DB_RESULT_HANDLER* ResultHandler,
void* ctx)
{
auto myctx = std::make_unique<CountContext>(ResultHandler, ctx);
bool status =
SqlQueryWithHandler(query.c_str(), CountingHandler, myctx.get());
Dmsg3(150, "Got %d NDMP environment records\n", myctx->count);
return status && myctx->count > 0; // no rows means no environment was found
}

/**
* Fetch the NDMP Job Environment Strings for NDMP_NATIVE Backups
* Fetch the NDMP Job Environment Strings based on JobId only
*
* Returns false: on failure
* true: on success
*/
bool BareosDb::GetNdmpEnvironmentString(JobControlRecord* jcr,
JobId_t JobId,
bool BareosDb::GetNdmpEnvironmentString(JobId_t JobId,
DB_RESULT_HANDLER* ResultHandler,
void* ctx)
{
PoolMem query(PM_FNAME);
char ed1[50];
db_int64_ctx lctx;
bool retval = false;
ASSERT(JobId > 0)
std::string query{"SELECT EnvName, EnvValue FROM NDMPJobEnvironment"};
query += " WHERE JobId=" + std::to_string(JobId);

/*
* Lookup all environment settings belonging to this JobId.
*/
Mmsg(query,
"SELECT EnvName, EnvValue FROM NDMPJobEnvironment "
"WHERE JobId='%s' ",
edit_uint64(JobId, ed1));
return GetNdmpEnvironmentString(query, ResultHandler, ctx);
}

retval = SqlQueryWithHandler(query.c_str(), ResultHandler, ctx);
/**
* Fetch the NDMP Job Environment Strings based on JobId and FileIndex
*
* Returns false: on failure
* true: on success
*/
bool BareosDb::GetNdmpEnvironmentString(JobId_t JobId,
int32_t FileIndex,
DB_RESULT_HANDLER* ResultHandler,
void* ctx)
{
ASSERT(JobId > 0)
std::string query{"SELECT EnvName, EnvValue FROM NDMPJobEnvironment"};
query += " WHERE JobId=" + std::to_string(JobId);
query += " AND FileIndex=" + std::to_string(FileIndex);

return retval;
return GetNdmpEnvironmentString(query, ResultHandler, ctx);
}


@@ -1746,48 +1794,28 @@ bool BareosDb::GetNdmpEnvironmentString(JobControlRecord* jcr,
* Returns false: on failure
* true: on success
*/
bool BareosDb::GetNdmpEnvironmentString(JobControlRecord* jcr,
JobDbRecord* jr,
bool BareosDb::GetNdmpEnvironmentString(const VolumeSessionInfo& vsi,
int32_t FileIndex,
DB_RESULT_HANDLER* ResultHandler,
void* ctx)
{
PoolMem query(PM_MESSAGE);
char ed1[50], ed2[50];
db_int64_ctx lctx;
JobId_t JobId;
bool retval = false;

lctx.count = 0;
lctx.value = 0;

/*
* Lookup the JobId
*/
Mmsg(query,
"SELECT JobId FROM Job "
"WHERE VolSessionId = '%s' "
"AND VolSessionTime = '%s'",
edit_uint64(jr->VolSessionId, ed1),
edit_uint64(jr->VolSessionTime, ed2));
if (!SqlQueryWithHandler(query.c_str(), db_int64_handler, &lctx)) {
goto bail_out;
std::string query{"SELECT JobId FROM Job"};
query += " WHERE VolSessionId = " + std::to_string(vsi.id);
query += " AND VolSessionTime = " + std::to_string(vsi.time);

if (SqlQueryWithHandler(query.c_str(), db_int64_handler, &lctx)) {
if (lctx.count == 1) {
/* now lctx.value contains the jobid we restore */
return GetNdmpEnvironmentString(lctx.value, FileIndex, ResultHandler,
ctx);
}
}

JobId = (JobId_t)lctx.value;

/*
* Lookup all environment settings belonging to this JobId and FileIndex.
*/
Mmsg(query,
"SELECT EnvName, EnvValue FROM NDMPJobEnvironment "
"WHERE JobId='%s' "
"AND FileIndex='%s'",
edit_uint64(JobId, ed1), edit_uint64(jr->FileIndex, ed2));

retval = SqlQueryWithHandler(query.c_str(), ResultHandler, ctx);

bail_out:
return retval;
Dmsg3(
100,
"Got %d JobIds for VolSessionTime=%lld VolSessionId=%lld instead of 1\n",
lctx.count, vsi.time, vsi.id);
return false;
}

/**
@@ -36,6 +36,7 @@
#include "dird/storage.h"

#include "lib/parse_bsr.h"
#include "lib/volume_session_info.h"

#if HAVE_NDMP
#include "dird/ndmp_dma_generic.h"
@@ -159,6 +160,7 @@ static inline int set_files_to_restore(JobControlRecord* jcr,
*/
static inline bool fill_restore_environment(JobControlRecord* jcr,
int32_t current_fi,
VolumeSessionInfo current_session,
struct ndm_job_param* job)
{
int i;
@@ -202,14 +204,16 @@ static inline bool fill_restore_environment(JobControlRecord* jcr,
/*
* Lookup the environment stack saved during the backup so we can restore it.
*/
if (!jcr->db->GetNdmpEnvironmentString(jcr, &jcr->jr, NdmpEnvHandler,
&job->env_tab)) {
if (!jcr->db->GetNdmpEnvironmentString(current_session, current_fi,
NdmpEnvHandler, &job->env_tab)) {
/*
* Fallback code try to build a environment stack that is good enough to
* restore this NDMP backup. This is used when the data is not available in
* the database when its either expired or when an old NDMP backup is
* restored where the whole environment was not saved.
*/
Jmsg(jcr, M_WARNING, 0,
_("Could not load NDMP environment. Using fallback.\n"));

if (!nbf_options || nbf_options->uses_file_history) {
/*
@@ -540,14 +544,13 @@ static inline bool DoNdmpRestoreBootstrap(JobControlRecord* jcr)
bool next_fi = true;
int first_fi = jcr->bsr->FileIndex->findex;
int last_fi = jcr->bsr->FileIndex->findex2;
uint32_t current_sessionid = jcr->bsr->sessid->sessid;
uint32_t current_sessiontime = jcr->bsr->sesstime->sesstime;
VolumeSessionInfo current_session{jcr->bsr->sessid->sessid,
jcr->bsr->sesstime->sesstime};
cnt = 0;

for (bsr = jcr->bsr; bsr; bsr = bsr->next) {
if (current_sessionid != bsr->sessid->sessid) {
current_sessionid = bsr->sessid->sessid;
current_sessiontime = bsr->sesstime->sesstime;
if (current_session.id != bsr->sessid->sessid) {
current_session = {bsr->sessid->sessid, bsr->sesstime->sesstime};
first_run = true;
next_sessid = true;
}
@@ -568,7 +571,7 @@ static inline bool DoNdmpRestoreBootstrap(JobControlRecord* jcr)
}
}
Dmsg4(20, "sessionid:sesstime : first_fi/last_fi : %d:%d %d/%d \n",
current_sessionid, current_sessiontime, first_fi, last_fi);
current_session.id, current_session.time, first_fi, last_fi);
}

if (next_sessid | next_fi) {
@@ -580,8 +583,8 @@ static inline bool DoNdmpRestoreBootstrap(JobControlRecord* jcr)
Jmsg(
jcr, M_INFO, 0,
_("Run restore for sesstime %s (%d), sessionid %d, fileindex %d\n"),
bstrftime(dt, sizeof(dt), current_sessiontime, NULL),
current_sessiontime, current_sessionid, current_fi);
bstrftime(dt, sizeof(dt), current_session.time, NULL),
current_session.time, current_session.id, current_fi);


/*
@@ -630,7 +633,7 @@ static inline bool DoNdmpRestoreBootstrap(JobControlRecord* jcr)

memcpy(&ndmp_sess.control_acb->job, &ndmp_job,
sizeof(struct ndm_job_param));
if (!fill_restore_environment(jcr, current_fi,
if (!fill_restore_environment(jcr, current_fi, current_session,
&ndmp_sess.control_acb->job)) {
Jmsg(jcr, M_ERROR, 0, _("ERROR in fill_restore_environment\n"));
goto cleanup_ndmp;
@@ -55,13 +55,10 @@ static inline bool fill_restore_environment_ndmp_native(
struct ndm_job_param* job)
{
ndmp9_pval pv;
char *ndmp_filesystem, *restore_prefix;
PoolMem tape_device;
PoolMem destination_path;
ndmp_backup_format_option* nbf_options;

ndmp_filesystem = NULL;

/*
* See if we know this backup format and get it options.
*/
@@ -73,59 +70,39 @@ static inline bool fill_restore_environment_ndmp_native(
* We use the first jobid to get the environment string
*/

JobId_t JobId = str_to_int32(jcr->JobIds);
// TODO: Check if JobId is Zero as this indicates error
JobId_t JobId{str_to_uint32(jcr->JobIds)};
if (JobId <= 0) {
Jmsg(jcr, M_FATAL, 0, "Impossible JobId: %d", JobId);
return false;
}

if (jcr->db->GetNdmpEnvironmentString(jcr, JobId, NdmpEnvHandler,
&job->env_tab)) {
/*
* extract ndmp_filesystem from environment
*/
for (struct ndm_env_entry* entry = job->env_tab.head; entry;
entry = entry->next) {
if (bstrcmp(entry->pval.name,
ndmp_env_keywords[NDMP_ENV_KW_FILESYSTEM])) {
ndmp_filesystem = entry->pval.value;
break;
}
}
} else {
/*
* Fallback code try to build a environment stack that is good enough to
* restore this NDMP backup. This is used when the data is not available in
* the database when its either expired or when an old NDMP backup is
* restored where the whole environment was not saved.
*/
if (!jcr->db->GetNdmpEnvironmentString(JobId, NdmpEnvHandler,
&job->env_tab)) {
Jmsg(jcr, M_FATAL, 0,
_("Could not load NDMP environment. Cannot continue without one.\n"));
return false;
}

if (!nbf_options || nbf_options->uses_file_history) {
/*
* We asked during the NDMP backup to receive file history info.
*/
pv.name = ndmp_env_keywords[NDMP_ENV_KW_HIST];
pv.value = ndmp_env_values[NDMP_ENV_VALUE_YES];
ndma_store_env_list(&job->env_tab, &pv);
/* try to extract ndmp_filesystem from environment */
char *ndmp_filesystem = nullptr;
for (struct ndm_env_entry* entry = job->env_tab.head; entry;
entry = entry->next) {
if (bstrcmp(entry->pval.name, ndmp_env_keywords[NDMP_ENV_KW_FILESYSTEM])) {
ndmp_filesystem = entry->pval.value;
break;
}

/*
* Tell the data agent what type of restore stream to expect.
*/
pv.name = ndmp_env_keywords[NDMP_ENV_KW_TYPE];
pv.value = job->bu_type;
ndma_store_env_list(&job->env_tab, &pv);

/*
* Tell the data engine what was backuped.
*/
pv.name = ndmp_env_keywords[NDMP_ENV_KW_FILESYSTEM];
pv.value = ndmp_filesystem;
ndma_store_env_list(&job->env_tab, &pv);
}

if (!ndmp_filesystem) {
Jmsg(jcr, M_FATAL, 0, _("No %s in NDMP environment. Cannot continue.\n"),
ndmp_env_keywords[NDMP_ENV_KW_FILESYSTEM]);
return false;
}

/*
* See where to restore the data.
*/
restore_prefix = NULL;
char* restore_prefix = nullptr;
if (jcr->where) {
restore_prefix = jcr->where;
} else {
Oops, something went wrong.

0 comments on commit 020ca8e

Please sign in to comment.
You can’t perform that action at this time.