Commit 152f3563 authored by Cedric Caffy's avatar Cedric Caffy
Browse files

[cta-admin] Implemented cta-admin recycletf ls [--vid] [--fxid] to list...

[cta-admin] Implemented cta-admin recycletf ls [--vid] [--fxid] to list content of the FILE_RECYCLE_LOG table
parent 717d76fb
......@@ -70,6 +70,7 @@
#include "common/log/Logger.hpp"
#include "common/optional.hpp"
#include "disk/DiskSystem.hpp"
#include "RecyleTapeFileSearchCriteria.hpp"
#include <list>
#include <map>
......@@ -872,7 +873,7 @@ public:
*
* @return The deleted archive files ordered by archive file ID.
*/
virtual FileRecycleLogItor getFileRecycleLogItor() const = 0;
virtual FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria = RecycleTapeFileSearchCriteria()) const = 0;
/**
* Returns the specified files in tape file sequence order.
......
......@@ -520,8 +520,8 @@ public:
return retryOnLostConnection(m_log, [&]{return m_catalogue->getArchiveFilesItor(searchCriteria);}, m_maxTriesToConnect);
}
FileRecycleLogItor getFileRecycleLogItor() const override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->getFileRecycleLogItor();}, m_maxTriesToConnect);
FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const override {
return retryOnLostConnection(m_log, [&]{return m_catalogue->getFileRecycleLogItor(searchCriteria);}, m_maxTriesToConnect);
}
void deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc){
......
......@@ -15822,6 +15822,7 @@ TEST_P(cta_catalogue_CatalogueTest, moveFilesToRecycleLog) {
for(auto & tapeItemWritten: tapeFilesWrittenCopy1){
cta::catalogue::TapeFileWritten * tapeItem = static_cast<cta::catalogue::TapeFileWritten *>(tapeItemWritten.get());
cta::common::dataStructures::DeleteArchiveRequest req;
req.requester.name = m_admin.username;
req.archiveFileID = tapeItem->archiveFileId;
req.diskFileId = tapeItem->diskFileId;
req.diskFilePath = tapeItem->diskFilePath;
......@@ -15863,7 +15864,7 @@ TEST_P(cta_catalogue_CatalogueTest, moveFilesToRecycleLog) {
ASSERT_EQ(cta::checksum::ChecksumBlob(checksum::ADLER32, "1357"),deletedArchiveFile.checksumBlob);
ASSERT_EQ(m_storageClassSingleCopy.name, deletedArchiveFile.storageClassName);
ASSERT_EQ(diskFileId.str(),deletedArchiveFile.diskFileIdWhenDeleted);
ASSERT_EQ(cta::catalogue::InsertFileRecycleLog::getDeletionReasonLog(m_admin.username,diskInstance),deletedArchiveFile.reasonLog);
ASSERT_EQ(tape1.vid, deletedArchiveFile.vid);
ASSERT_EQ(i,deletedArchiveFile.fSeq);
ASSERT_EQ(i * 100,deletedArchiveFile.blockId);
......@@ -15985,6 +15986,17 @@ TEST_P(cta_catalogue_CatalogueTest, emptyFileRecycleLogItorTest) {
ASSERT_THROW(itor.next(),cta::exception::Exception);
}
 
TEST_P(cta_catalogue_CatalogueTest, getFileRecycleLogItorVidNotExists) {
using namespace cta;
auto itor = m_catalogue->getFileRecycleLogItor();
ASSERT_FALSE(m_catalogue->getFileRecycleLogItor().hasMore());
catalogue::RecycleTapeFileSearchCriteria criteria;
criteria.vid = "NOT_EXISTS";
ASSERT_THROW(m_catalogue->getFileRecycleLogItor(criteria),exception::UserError);
}
TEST_P(cta_catalogue_CatalogueTest, filesArePutInTheFileRecycleLogInsteadOfBeingSuperseded) {
using namespace cta;
 
......@@ -16105,10 +16117,41 @@ TEST_P(cta_catalogue_CatalogueTest, filesArePutInTheFileRecycleLogInsteadOfBeing
ASSERT_EQ(fileRecycleLog.storageClassName,fileWrittenPtr->storageClassName);
ASSERT_EQ(fileRecycleLog.reconciliationTime,fileRecycleLog.archiveFileCreationTime);
ASSERT_EQ(cta::nullopt, fileRecycleLog.collocationHint);
ASSERT_EQ(cta::nullopt, fileRecycleLog.diskFilePath);\
ASSERT_EQ(cta::nullopt, fileRecycleLog.diskFilePath);
ASSERT_EQ(cta::catalogue::InsertFileRecycleLog::getRepackReasonLog(),fileRecycleLog.reasonLog);
}
}
{
//Check the vid search criteria
catalogue::RecycleTapeFileSearchCriteria criteria;
criteria.vid = tape1.vid;
auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria);
int nbFileRecycleLogs = 0;
while(fileRecycleLogItor.hasMore()){
nbFileRecycleLogs++;
fileRecycleLogItor.next();
}
ASSERT_EQ(nbArchiveFiles,nbFileRecycleLogs);
}
{
//Check the diskFileId search criteria
std::string diskFileId = "12345678";
catalogue::RecycleTapeFileSearchCriteria criteria;
criteria.diskFileId = diskFileId;
auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria);
ASSERT_TRUE(fileRecycleLogItor.hasMore());
auto fileRecycleLog = fileRecycleLogItor.next();
ASSERT_EQ(diskFileId,fileRecycleLog.diskFileId);
ASSERT_FALSE(fileRecycleLogItor.hasMore());
}
{
//Check the non existing diskFileId search criteria
std::string diskFileId = "DOES_NOT_EXIST";
catalogue::RecycleTapeFileSearchCriteria criteria;
criteria.diskFileId = diskFileId;
auto fileRecycleLogItor = m_catalogue->getFileRecycleLogItor(criteria);
ASSERT_FALSE(fileRecycleLogItor.hasMore());
}
}
 
TEST_P(cta_catalogue_CatalogueTest, sameFileWrittenToSameTapePutThePreviousCopyOnTheFileRecycleLog) {
......
......@@ -82,7 +82,7 @@ public:
std::list<common::dataStructures::AdminUser> getAdminUsers() const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
common::dataStructures::ArchiveFile getArchiveFileById(const uint64_t id) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
ArchiveFileItor getArchiveFilesItor(const TapeFileSearchCriteria& searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
FileRecycleLogItor getFileRecycleLogItor() const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
void deleteFileFromRecycleBin(const uint64_t archiveFileId, log::LogContext &lc) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");}
void deleteFilesFromRecycleLog(const std::string & vid, log::LogContext & lc) {throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented");}
std::list<common::dataStructures::ArchiveFile> getFilesForRepack(const std::string &vid, const uint64_t startFSeq, const uint64_t maxNbFiles) const override { throw exception::Exception(std::string("In ")+__PRETTY_FUNCTION__+": not implemented"); }
......
......@@ -6793,9 +6793,22 @@ Catalogue::ArchiveFileItor RdbmsCatalogue::getTapeContentsItor(const std::string
}
}
Catalogue::FileRecycleLogItor RdbmsCatalogue::getFileRecycleLogItor() const {
//------------------------------------------------------------------------------
// checkRecycleTapeFileSearchCriteria
//------------------------------------------------------------------------------
void RdbmsCatalogue::checkRecycleTapeFileSearchCriteria(const RecycleTapeFileSearchCriteria & searchCriteria) const {
if(searchCriteria.vid) {
auto conn = m_connPool.getConn();
if(!tapeExists(conn, searchCriteria.vid.value())) {
throw exception::UserError(std::string("Tape ") + searchCriteria.vid.value() + " does not exist");
}
}
}
Catalogue::FileRecycleLogItor RdbmsCatalogue::getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const {
try {
auto impl = new RdbmsCatalogueGetFileRecycleLogItor(m_log, m_archiveFileListingConnPool);
checkRecycleTapeFileSearchCriteria(searchCriteria);
auto impl = new RdbmsCatalogueGetFileRecycleLogItor(m_log, m_archiveFileListingConnPool, searchCriteria);
return FileRecycleLogItor(impl);
} catch(exception::UserError &) {
throw;
......
......@@ -837,12 +837,21 @@ public:
*/
ArchiveFileItor getArchiveFilesItor(const TapeFileSearchCriteria &searchCriteria) const override;
/**
* Throws a UserError exception if the specified searchCriteria is not valid
* due to a user error.
*
* @param searchCriteria The search criteria.
*/
void checkRecycleTapeFileSearchCriteria(const RecycleTapeFileSearchCriteria & searchCriteria) const;
/**
* Returns all the currently deleted files by looking at the FILE_RECYCLE_LOG table
*
* @param searchCriteria The search criteria
* @return The deleted archive files ordered by archive file ID.
*/
FileRecycleLogItor getFileRecycleLogItor() const override;
FileRecycleLogItor getFileRecycleLogItor(const RecycleTapeFileSearchCriteria & searchCriteria) const override;
/**
* Returns the specified files in tape file sequence order.
......
......@@ -28,9 +28,11 @@ namespace catalogue {
//------------------------------------------------------------------------------
RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor(
log::Logger &log,
rdbms::ConnPool &connPool):
rdbms::ConnPool &connPool,
const RecycleTapeFileSearchCriteria & searchCriteria):
m_log(log),
m_connPool(connPool),
m_searchCriteria(searchCriteria),
m_rsetIsEmpty(true),
m_hasMoreHasBeenCalled(false) {
try {
......@@ -61,11 +63,47 @@ RdbmsCatalogueGetFileRecycleLogItor::RdbmsCatalogueGetFileRecycleLogItor(
"FROM "
"FILE_RECYCLE_LOG "
"JOIN "
"STORAGE_CLASS ON STORAGE_CLASS.STORAGE_CLASS_ID = FILE_RECYCLE_LOG.STORAGE_CLASS_ID "
"ORDER BY FILE_RECYCLE_LOG.ARCHIVE_FILE_ID, FILE_RECYCLE_LOG.COPY_NB";
"STORAGE_CLASS ON STORAGE_CLASS.STORAGE_CLASS_ID = FILE_RECYCLE_LOG.STORAGE_CLASS_ID";
const bool thereIsAtLeastOneSearchCriteria =
searchCriteria.vid ||
searchCriteria.diskFileId;
if(thereIsAtLeastOneSearchCriteria) {
sql += " WHERE ";
}
bool addedAWhereConstraint = false;
if(searchCriteria.vid) {
sql += "FILE_RECYCLE_LOG.VID = :VID";
addedAWhereConstraint = true;
}
if(searchCriteria.diskFileId){
if(addedAWhereConstraint) sql += " AND ";
sql += "FILE_RECYCLE_LOG.DISK_FILE_ID = :DISK_FILE_ID";
addedAWhereConstraint = true;
}
// Order by FSEQ if we are listing the contents of a tape, else order by archive file ID
if(searchCriteria.vid) {
sql += " ORDER BY FILE_RECYCLE_LOG.FSEQ";
} else {
sql += " ORDER BY FILE_RECYCLE_LOG.ARCHIVE_FILE_ID, FILE_RECYCLE_LOG.COPY_NB";
}
m_conn = connPool.getConn();
m_stmt = m_conn.createStmt(sql);
if(searchCriteria.vid){
m_stmt.bindString(":VID", searchCriteria.vid.value());
}
if(searchCriteria.diskFileId){
m_stmt.bindString(":DISK_FILE_ID", searchCriteria.diskFileId.value());
}
m_rset = m_stmt.executeQuery();
m_rsetIsEmpty = !m_rset.next();
......
......@@ -32,7 +32,7 @@ public:
* @param log Object representing the API to the CTA logging system.
* @param connPool The database connection pool.
*/
RdbmsCatalogueGetFileRecycleLogItor(log::Logger &log, rdbms::ConnPool &connPool);
RdbmsCatalogueGetFileRecycleLogItor(log::Logger &log, rdbms::ConnPool &connPool, const RecycleTapeFileSearchCriteria & searchCriteria);
/**
* Destructor.
......@@ -59,6 +59,11 @@ private:
* The database connection pool.
*/
rdbms::ConnPool &m_connPool;
/**
* The search criteria to be used when listing recycled tape files.
*/
RecycleTapeFileSearchCriteria m_searchCriteria;
/**
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2019 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <vector>
#include "common/optional.hpp"
namespace cta {
namespace catalogue {
/**
* The collection of criteria used to select a set of tape files.
* A tape file is selected if it meets all of the specified criteria.
* A criterion is only considered specified if it has been set.
* Please note that no wild cards, for example '*' or '%', are supported.
*/
struct RecycleTapeFileSearchCriteria {
/**
* The volume identifier of a tape.
*/
optional<std::string> vid;
/**
* List of disk file IDs.
*
* These are given as a list of strings in DECIMAL format. EOS provides the fxids in hex format. The parsing and
* conversion into decimal is done in the cta-admin client, ready to be built into a SQL query string.
*/
optional<std::string> diskFileId;
}; // struct TapeFileSearchCriteria
} // namespace catalogue
} // namespace cta
......@@ -107,6 +107,7 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
case Data::kVersionItem: std::cout << Log::DumpProtobuf(&record.version_item()); break;
case Data::kMtlsItem: std::cout << Log::DumpProtobuf(&record.mtls_item()); break;
case Data::kSilsItem: std::cout << Log::DumpProtobuf(&record.sils_item()); break;
case Data::kRtflsItem: std::cout << Log::DumpProtobuf(&record.rtfls_item()); break;
default:
throw std::runtime_error("Received invalid stream data from CTA Frontend.");
}
......@@ -136,6 +137,7 @@ void IStreamBuffer<cta::xrd::Data>::DataCallback(cta::xrd::Data record) const
case Data::kVolsItem: formattedText.print(record.vols_item()); break;
case Data::kVersionItem: formattedText.print(record.version_item()); break;
case Data::kMtlsItem: formattedText.print(record.mtls_item()); break;
case Data::kRtflsItem: formattedText.print(record.rtfls_item()); break;
case Data::kSilsItem: break;
default:
throw std::runtime_error("Received invalid stream data from CTA Frontend.");
......@@ -296,7 +298,8 @@ void CtaAdminCmd::send() const
case HeaderType::VIRTUALORGANIZATION_LS: formattedText.printVirtualOrganizationLsHeader(); break;
case HeaderType::VERSION_CMD: formattedText.printVersionHeader(); break;
case HeaderType::MEDIATYPE_LS: formattedText.printMediaTypeLsHeader(); break;
case HeaderType::SCHEDULINGINFOS_LS: formattedText.printSchedulingInfosLsHeader(); break;
case HeaderType::SCHEDULINGINFOS_LS: formattedText.printSchedulingInfosLsHeader(); break;
case HeaderType::RECYLETAPEFILE_LS: formattedText.printRecycleTapeFileLsHeader(); break;
case HeaderType::NONE:
default: break;
}
......
......@@ -217,6 +217,8 @@ const cmdLookup_t cmdLookup = {
{ "v", AdminCmd::CMD_VERSION},
{ "schedulinginfo", AdminCmd::CMD_SCHEDULINGINFOS},
{ "si", AdminCmd::CMD_SCHEDULINGINFOS},
{ "recycletf", AdminCmd::CMD_RECYCLETAPEFILE},
{ "rtf", AdminCmd::CMD_RECYCLETAPEFILE},
};
......@@ -395,6 +397,9 @@ const std::map<AdminCmd::Cmd, CmdHelp> cmdHelp = {
{ AdminCmd::CMD_VIRTUALORGANIZATION, { "virtualorganization", "vo", { "add", "ch", "rm", "ls" } }},
{ AdminCmd::CMD_VERSION, { "version", "v", { } }},
{ AdminCmd::CMD_SCHEDULINGINFOS, { "schedulinginfo", "si", { "ls" } }},
{ AdminCmd::CMD_RECYCLETAPEFILE, { "recycletf", "rtf", { "ls" },
" Tape files in the recycle log can be listed by VID or by EOS disk file ID.\n"
" Disk file IDs should be provided in hexadecimal (fxid).\n\n" }},
};
......@@ -596,6 +601,7 @@ const std::map<cmd_key_t, cmd_val_t> cmdOptions = {
{ }},
{{ AdminCmd::CMD_VERSION, AdminCmd::SUBCMD_NONE }, { }},
{{ AdminCmd::CMD_SCHEDULINGINFOS, AdminCmd::SUBCMD_LS }, { }},
{{ AdminCmd::CMD_RECYCLETAPEFILE, AdminCmd::SUBCMD_LS }, { opt_vid.optional(), opt_fid.optional() }},
};
......
......@@ -1047,4 +1047,61 @@ void TextFormatter::printSchedulingInfosLsHeader(){
push_back("No tabular output available for this command, please use the --json flag.");
}
void TextFormatter::printRecycleTapeFileLsHeader() {
push_back("HEADER");
push_back(
"archive id",
"copy no",
"vid",
"fseq",
"block id",
"instance",
"disk fxid",
"size",
"checksum type",
"checksum value",
"storage class",
"owner",
"group",
"deletion time",
"path when deleted",
"reason"
);
}
void TextFormatter::print(const RecycleTapeFileLsItem & rtfls_item){
// Files can have multiple checksums of different types. The tabular output will
// display only the first checksum; the JSON output will list all checksums.
std::string checksumType("NONE");
std::string checksumValue;
if(!rtfls_item.checksum().empty()) {
const google::protobuf::EnumDescriptor *descriptor = cta::common::ChecksumBlob::Checksum::Type_descriptor();
checksumType = descriptor->FindValueByNumber(rtfls_item.checksum().begin()->type())->name();
checksumValue = rtfls_item.checksum().begin()->value();
}
auto fid = strtol(rtfls_item.disk_file_id().c_str(), nullptr, 10);
std::stringstream fxid;
fxid << std::hex << fid;
push_back(
rtfls_item.archive_file_id(),
rtfls_item.copy_nb(),
rtfls_item.vid(),
rtfls_item.fseq(),
rtfls_item.block_id(),
rtfls_item.disk_instance(),
fxid.str(),
dataSizeToStr(rtfls_item.size_in_bytes()),
checksumType,
checksumValue,
rtfls_item.storage_class(),
rtfls_item.disk_file_uid(),
rtfls_item.disk_file_gid(),
timeToStr(rtfls_item.recycle_log_time()),
rtfls_item.disk_file_path(),
rtfls_item.reason_log()
);
}
}}
......@@ -68,6 +68,7 @@ public:
void printVersionHeader();
void printMediaTypeLsHeader();
void printSchedulingInfosLsHeader();
void printRecycleTapeFileLsHeader();
// Output records
void print(const AdminLsItem &adls_item);
......@@ -93,6 +94,7 @@ public:
void print(const VirtualOrganizationLsItem &vols_item);
void print(const VersionItem & version_item);
void print(const MediaTypeLsItem &mtls_item);
void print(const RecycleTapeFileLsItem & rtfls_item);
private:
......
......@@ -146,8 +146,8 @@ repackJustMove() {
exit 1
fi
echo "Reclaiming tape ${VID_TO_REPACK}"
kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK}
echo "NOT Reclaiming tape ${VID_TO_REPACK}"
#kubectl -n ${NAMESPACE} exec ctacli -- cta-admin tape reclaim --vid ${VID_TO_REPACK}
echo
echo "*****************************************************"
echo "STEP $1. Testing Repack \"Just move\" workflow TEST OK"
......@@ -569,12 +569,12 @@ repackTapeRepairNoRecall() {
}
#Execution of each tests
roundTripRepack 1
repackDisableTape 2
#roundTripRepack 1
#repackDisableTape 2
archiveFiles 1152 15
repackJustMove 3
repackTapeRepair 4
repackJustAddCopies 5
repackCancellation 6
# repackMoveAndAddCopies 7
repackTapeRepairNoRecall 7
#repackTapeRepair 4
#repackJustAddCopies 5
#repackCancellation 6
## repackMoveAndAddCopies 7
#repackTapeRepairNoRecall 7
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2019 CERN
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "catalogue/Catalogue.hpp"
namespace cta { namespace xrd {
/*!
* Stream object which implements "recycletf ls" command
*/
class RecycleTapeFileLsStream: public XrdCtaStream{
public:
/*!
* Constructor
*
* @param[in] requestMsg RequestMessage containing command-line arguments
* @param[in] catalogue CTA Catalogue
* @param[in] scheduler CTA Scheduler
*/
RecycleTapeFileLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler);
private:
/*!
* Can we close the stream?
*/
virtual bool isDone() const {
return !m_fileRecycleLogItor.hasMore();
}
/*!
* Fill the buffer
*/
virtual int fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf);
cta::catalogue::Catalogue::FileRecycleLogItor m_fileRecycleLogItor; //!< List of recycle tape files from the catalogue
static constexpr const char* const LOG_SUFFIX = "RecycleTapeFileLsStream"; //!< Identifier for log messages
};
RecycleTapeFileLsStream::RecycleTapeFileLsStream(const RequestMessage &requestMsg, cta::catalogue::Catalogue &catalogue, cta::Scheduler &scheduler) :
XrdCtaStream(catalogue, scheduler)
{
using namespace cta::admin;
bool has_any = false;
cta::catalogue::RecycleTapeFileSearchCriteria searchCriteria;
searchCriteria.vid = requestMsg.getOptional(OptionString::VID, &has_any);
auto diskFileId = requestMsg.getOptional(OptionString::FXID, &has_any);
if(diskFileId){
// single option on the command line we need to do the conversion ourselves.
auto fid = strtol(diskFileId->c_str(), nullptr, 16);
if(fid < 1 || fid == LONG_MAX) {
throw cta::exception::UserError(*diskFileId + " is not a valid file ID");
}
searchCriteria.diskFileId = std::to_string(fid);
}
if(!has_any){
throw cta::exception::UserError("Must specify at least one search option");
}
m_fileRecycleLogItor = catalogue.getFileRecycleLogItor(searchCriteria);
XrdSsiPb::Log::Msg(XrdSsiPb::Log::DEBUG, LOG_SUFFIX, "RecycleTapeFileLsStream() constructor");
}
int RecycleTapeFileLsStream::fillBuffer(XrdSsiPb::OStreamBuffer<Data> *streambuf) {
for(bool is_buffer_full = false; m_fileRecycleLogItor.hasMore() && !is_buffer_full; ) {
const common::dataStructures::FileRecycleLog fileRecycleLog = m_fileRecycleLogItor.next();
Data record;
auto recycleLogToReturn = record.mutable_rtfls_item();
recycleLogToReturn->set_vid(fileRecycleLog.vid);
recycleLogToReturn->set_fseq(fileRecycleLog.fSeq);
recycleLogToReturn->set_block_id(fileRecycleLog.blockId);
recycleLogToReturn->set_logical_size_in_bytes(fileRecycleLog.logicalSizeInBytes);
recycleLogToReturn->set_copy_nb(fileRecycleLog.copyNb);
recycleLogToReturn->set_tape_file_creation_time(fileRecycleLog.tapeFileCreationTime);
recycleLogToReturn->set_archive_file_id(fileRecycleLog.archiveFileId);
recycleLogToReturn->set_disk_instance(fileRecycleLog.diskInstanceName);
recycleLogToReturn->set_disk_file_id(fileRecycleLog.diskFileId);
recycleLogToReturn->set_disk_file_id_when_deleted(fileRecycleLog.diskFileIdWhenDeleted);
recycleLogToReturn->set_disk_file_uid(fileRecycleLog.diskFileUid);
recycleLogToReturn->set_disk_file_gid(fileRecycleLog.diskFileGid);
recycleLogToReturn->set_size_in_bytes(fileRecycleLog.sizeInBytes);
// Checksum
common::ChecksumBlob csb;
checksum::ChecksumBlobToProtobuf(fileRecycleLog.checksumBlob, csb);
for(auto csb_it = csb.cs().begin(); csb_it != csb.cs().end(); ++csb_it) {
auto cs_ptr = recycleLogToReturn->add_checksum();
cs_ptr->set_type(csb_it->type());
cs_ptr->set_value(checksum::ChecksumBlob::ByteArrayToHex(csb_it->value()));
}
recycleLogToReturn->set_storage_class(fileRecycleLog.storageClassName);
recycleLogToReturn->set_archive_file_creation_time(fileRecycleLog.archiveFileCreationTime);
recycleLogToReturn->set_reconciliation_time(fileRecycleLog.reconciliationTime);
if(fileRecycleLog.collocationHint){
recycleLogToReturn->set_collocation_hint(fileRecycleLog.collocationHint.value());
}
if(fileRecycleLog.diskFilePath){
recycleLogToReturn->set_disk_file_path(fileRecycleLog.diskFilePath.value());
}
recycleLogToReturn->set_reason_log(fileRecycleLog.reasonLog);
recycleLogToReturn->set_recycle_log_time(fileRecycleLog.recycleLogTime);
// is_buffer_full is set to true when we have one full block of data in the buffer, i.e.
// enough data to send to the client. The actual buffer size is double the block size,
// so we can keep writing a few additional records after is_buffer_full is true. These
// will be sent on the next iteration. If we exceed the hard limit of double the block
// size, Push() will throw an exception.
is_buffer_full = streambuf->Push(record);
}
return streambuf->Size();