Skip to content

Commit

Permalink
added truncate command
Browse files Browse the repository at this point in the history
The truncate command allows to truncate purged volumes.
This can be use to free some disk space.
  • Loading branch information
joergsteffens committed Nov 16, 2016
1 parent a5c1550 commit 1ebe9c9
Show file tree
Hide file tree
Showing 13 changed files with 507 additions and 77 deletions.
6 changes: 5 additions & 1 deletion src/cats/cats.h
Expand Up @@ -66,9 +66,13 @@ class dbid_list : public SMARTALLOC {

dbid_list(); /* in sql.c */
~dbid_list(); /* in sql.c */

int size() const { return num_ids; }
DBId_t get(int i) const;
};

/* Job information passed to create job record and update
/*
* Job information passed to create job record and update
* job record at end of job. Note, although this record
* contains all the fields found in the Job database record,
* it also contains fields found in the JobMedia record.
Expand Down
8 changes: 7 additions & 1 deletion src/cats/protos.h
Expand Up @@ -102,11 +102,13 @@ int db_get_num_pool_records(JCR *jcr, B_DB *mdb);
int db_get_pool_ids(JCR *jcr, B_DB *mdb, int *num_ids, DBId_t **ids);
bool db_get_client_ids(JCR *jcr, B_DB *mdb, int *num_ids, DBId_t **ids);
int db_get_storage_ids(JCR *jcr, B_DB *mdb, int *num_ids, DBId_t **ids);
bool prepare_media_sql_query(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, POOL_MEM &volumes);
bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, POOL_MEM &volumes, int *num_ids, DBId_t **ids);
bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
bool verify_media_ids_from_single_storage(JCR *jcr, B_DB *mdb, dbid_list &ids);
int db_get_job_volume_parameters(JCR *jcr, B_DB *mdb, JobId_t JobId, VOL_PARAMS **VolParams);
bool db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr);
bool db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
bool use_md5, bool use_delta,
DB_RESULT_HANDLER *result_handler, void *ctx);
Expand Down Expand Up @@ -147,6 +149,10 @@ bool db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query,
bool db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query,
OUTPUT_FORMATTER *sendit, e_list_type type,
const char *description, bool verbose = false);
bool db_list_sql_query_start(JCR *jcr, B_DB *mdb, const char *query,
OUTPUT_FORMATTER *sendit, e_list_type type,
const char *description, bool verbose = false);
void db_list_sql_query_end(JCR *jcr, B_DB *mdb);
void db_list_client_records(JCR *jcr, B_DB *mdb, char *clientname,
OUTPUT_FORMATTER *sendit, e_list_type type);
void db_list_storage_records(JCR *jcr, B_DB *mdb,
Expand Down
11 changes: 11 additions & 0 deletions src/cats/sql.c
Expand Up @@ -56,6 +56,17 @@ dbid_list::~dbid_list()
free(DBId);
}

DBId_t dbid_list::get(int i) const {
if (i >= size()) {
Emsg2(M_ERROR_TERM, 0,
_("Unable to access dbid_list entry %d. Only %d entries available.\n"),
i, size());
return (DBId_t)0;
}
return DBId[i];
}


/*
* Called here to retrieve an integer from the database
*/
Expand Down
158 changes: 115 additions & 43 deletions src/cats/sql_get.c
Expand Up @@ -953,91 +953,138 @@ int db_get_num_media_records(JCR *jcr, B_DB *mdb)
}

/**
* This function returns a list of all the Media record ids for
* This function creates a sql query string at mdb->cmd to return a list of all the Media records for
* the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes and
* volumes or VolumeName if specified. Comma separated list of volumes takes precedence
* over VolumeName. The caller must free ids if non-NULL.
*
* Returns false: on failure
* true: on success
*/
bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, POOL_MEM &volumes, int *num_ids, DBId_t **ids)
bool prepare_media_sql_query(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, POOL_MEM &volumes)
{
SQL_ROW row;
int i = 0;
DBId_t *id;
bool ok = true;
char ed1[50];
bool ok = false;
char esc[MAX_NAME_LENGTH * 2 + 1];
bool have_volumes = false;
POOL_MEM buf(PM_MESSAGE);

db_lock(mdb);
*ids = NULL;

if (*volumes.c_str()) {
have_volumes = true;
}
/*
* columns we care of.
* Reduced, to be better displayable.
* Important:
* column 2: pool.name, column 3: storage.name,
* as this is used for ACL handling (counting starts at 0).
*/
const char *columns =
"Media.MediaId,"
"Media.VolumeName,"
"Pool.Name AS Pool,"
"Storage.Name AS Storage,"
"Media.MediaType,"
/* "Media.DeviceId," */
/* "Media.FirstWritten, "*/
"Media.LastWritten,"
"Media.VolFiles,"
"Media.VolBytes,"
"Media.VolStatus,"
/* "Media.Recycle AS Recycle," */
"Media.ActionOnPurge,"
/* "Media.VolRetention," */
"Media.Comment";

Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
mr->Recycle, mr->Enabled);
Mmsg(mdb->cmd,
"SELECT DISTINCT %s FROM Media "
"LEFT JOIN Pool USING(PoolId) "
"LEFT JOIN Storage USING(StorageId) "
"WHERE Media.Recycle=%d AND Media.Enabled=%d ",
columns, mr->Recycle, mr->Enabled);

if (*mr->MediaType) {
db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
Mmsg(buf, "AND MediaType='%s' ", esc);
Mmsg(buf, "AND Media.MediaType='%s' ", esc);
pm_strcat(mdb->cmd, buf.c_str());
}

if (mr->StorageId) {
Mmsg(buf, "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
Mmsg(buf, "AND Media.StorageId=%s ", edit_uint64(mr->StorageId, ed1));
pm_strcat(mdb->cmd, buf.c_str());
}

if (mr->PoolId) {
Mmsg(buf, "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
Mmsg(buf, "AND Media.PoolId=%s ", edit_uint64(mr->PoolId, ed1));
pm_strcat(mdb->cmd, buf.c_str());
}

if (mr->VolBytes) {
Mmsg(buf, "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
Mmsg(buf, "AND Media.VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
pm_strcat(mdb->cmd, buf.c_str());
}

if (*mr->VolStatus) {
db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
Mmsg(buf, "AND VolStatus = '%s' ", esc);
Mmsg(buf, "AND Media.VolStatus = '%s' ", esc);
pm_strcat(mdb->cmd, buf.c_str());
}

if (*mr->VolumeName && !have_volumes) {
if (volumes.strlen() > 0) {
/* extra list of volumes given */
Mmsg(buf, "AND Media.VolumeName IN (%s) ", volumes.c_str());
pm_strcat(mdb->cmd, buf.c_str());
} else if (*mr->VolumeName) {
/* single volume given in media record */
db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
Mmsg(buf, "AND VolumeName = '%s' ", esc);
Mmsg(buf, "AND Media.VolumeName = '%s' ", esc);
pm_strcat(mdb->cmd, buf.c_str());
}

if (have_volumes) {
Mmsg(buf, "AND VolumeName IN (%s) ", volumes.c_str());
pm_strcat(mdb->cmd, buf.c_str());
}
Dmsg1(100, "query=%s\n", mdb->cmd);

Dmsg1(100, "q=%s\n", mdb->cmd);
return ok;
}

if (QUERY_DB(jcr, mdb, mdb->cmd)) {
*num_ids = sql_num_rows(mdb);
if (*num_ids > 0) {
id = (DBId_t *)malloc(*num_ids * sizeof(DBId_t));
while ((row = sql_fetch_row(mdb)) != NULL) {
id[i++] = str_to_uint64(row[0]);
}
*ids = id;
}
sql_free_result(mdb);
ok = true;
} else {



/**
* This function returns a list of all the Media record ids for
* the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes and
* volumes or VolumeName if specified. Comma separated list of volumes takes precedence
* over VolumeName. The caller must free ids if non-NULL.
*
* Returns false: on failure
* true: on success
*/
bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, POOL_MEM &volumes, int *num_ids, DBId_t **ids)
{
bool ok = false;
SQL_ROW row;
int i = 0;
DBId_t *id;

db_lock(mdb);
*ids = NULL;

if (!prepare_media_sql_query(jcr, mdb, mr, volumes)) {
Mmsg(mdb->errmsg, _("Media id select failed: invalid parameter"));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
goto bail_out;
}

if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
Mmsg(mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
ok = false;
goto bail_out;
}

*num_ids = sql_num_rows(mdb);
if (*num_ids > 0) {
id = (DBId_t *)malloc(*num_ids * sizeof(DBId_t));
while ((row = sql_fetch_row(mdb)) != NULL) {
id[i++] = str_to_uint64(row[0]);
}
*ids = id;
}
sql_free_result(mdb);
ok = true;

bail_out:
db_unlock(mdb);
return ok;
}
Expand Down Expand Up @@ -1078,6 +1125,31 @@ bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids)
return ok;
}

bool verify_media_ids_from_single_storage(JCR *jcr, B_DB *mdb, dbid_list &mediaIds)
{
MEDIA_DBR mr;
DBId_t storageId = 0;

/*
* verify that all media use the same storage.
*/
for (int i = 0; i < mediaIds.size(); i++) {
memset(&mr, 0, sizeof(mr));
mr.MediaId = mediaIds.get(i);
if (!db_get_media_record(jcr, mdb, &mr)) {
Mmsg1(mdb->errmsg, _("Failed to find MediaId=%lld\n"), (uint64_t)mr.MediaId);
Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
return false;
} else if (i == 0) {
storageId = mr.StorageId;
} else if (storageId != mr.StorageId) {
return false;
}
}
return true;
}


/**
* Get Media Record
*
Expand Down
26 changes: 21 additions & 5 deletions src/cats/sql_list.c
Expand Up @@ -57,24 +57,40 @@ bool db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query,
{
bool retval = false;

if (db_list_sql_query_start(jcr, mdb, query, sendit, type, description, verbose)) {
retval = true;
db_list_sql_query_end(jcr, mdb);
}

return retval;
}

bool db_list_sql_query_start(JCR *jcr, B_DB *mdb, const char *query,
OUTPUT_FORMATTER *sendit, e_list_type type,
const char *description, bool verbose)
{
db_lock(mdb);
if (!sql_query(mdb, query, QF_STORE_RESULT)) {
Mmsg(mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb));
if (verbose) {
sendit->decoration(mdb->errmsg);
}
goto bail_out;
db_unlock(mdb);
return false;
}

sendit->array_start(description);
list_result(jcr, mdb, sendit, type);
sendit->array_end(description);
sql_free_result(mdb);
retval = true;

bail_out:
return true;
}


void db_list_sql_query_end(JCR *jcr, B_DB *mdb)
{
sql_free_result(mdb);
db_unlock(mdb);
return retval;
}

void db_list_pool_records(JCR *jcr, B_DB *mdb, POOL_DBR *pdbr,
Expand Down
5 changes: 5 additions & 0 deletions src/dird/protos.h
Expand Up @@ -335,12 +335,17 @@ bool get_cmd(UAContext *ua, const char *prompt, bool subprompt = false);
bool get_pint(UAContext *ua, const char *prompt);
bool get_yesno(UAContext *ua, const char *prompt);
bool is_yesno(char *val, bool *ret);
bool get_confirmation(UAContext *ua, const char *prompt = _("Confirm (yes/no): "));
int get_enabled(UAContext *ua, const char *val);
void parse_ua_args(UAContext *ua);
bool is_comment_legal(UAContext *ua, const char *name);

/* ua_label.c */
bool is_volume_name_legal(UAContext *ua, const char *name);
bool send_label_request(UAContext *ua,
STORERES *store, MEDIA_DBR *mr, MEDIA_DBR *omr, POOL_DBR *pr,
bool media_record_exists, bool relabel,
drive_number_t drive, slot_number_t slot);

/* ua_update.c */
void update_vol_pool(UAContext *ua, char *val, MEDIA_DBR *mr, POOL_DBR *opr);
Expand Down

0 comments on commit 1ebe9c9

Please sign in to comment.