diff --git a/objectstore/DriveState.cpp b/objectstore/DriveState.cpp index 5a7c16b6bfe5000eaa8318c6e7291ef6b76ca6fc..b9795e39125419b3be455aa321a562902335c9c4 100644 --- a/objectstore/DriveState.cpp +++ b/objectstore/DriveState.cpp @@ -281,6 +281,8 @@ void DriveState::setConfig(const cta::tape::daemon::TapedConfiguration& tapedCon fillConfig(config->mountCriteria); fillConfig(config->nbDiskThreads); fillConfig(config->useRAO); + fillConfig(config->raoLtoAlgorithm); + fillConfig(config->raoLtoOptions); fillConfig(config->wdScheduleMaxSecs); fillConfig(config->wdMountMaxSecs); fillConfig(config->wdNoBlockMoveMaxSecs); diff --git a/tapeserver/castor/tape/tapeserver/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/CMakeLists.txt index 55f323c01c72375ddd6c903e6781592c296e1543..9a73c25155cff2d7a70544224abdb7dc8bf5349a 100644 --- a/tapeserver/castor/tape/tapeserver/CMakeLists.txt +++ b/tapeserver/castor/tape/tapeserver/CMakeLists.txt @@ -41,6 +41,7 @@ add_subdirectory(drive) add_subdirectory(system) add_subdirectory(file) add_subdirectory(daemon) +add_subdirectory(RAO) # .. and of course, the tests (last to use the variable definition) add_subdirectory(test) diff --git a/tapeserver/castor/tape/tapeserver/RAO/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/RAO/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..152ce09ee0fe42975106778b77ca1ebde226679c --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required (VERSION 2.6) + +include_directories(${PROJECT_SOURCE_DIR}/tapeserver) +include_directories(${PROJECT_SOURCE_DIR}/tapeserver/h) + +set(CTARAO_LIBRARY_SRCS + RAOConfig.cpp + RAOManager.cpp + RAOAlgorithm.cpp + EnterpriseRAOAlgorithm.cpp + RAOAlgorithmFactory.cpp + EnterpriseRAOAlgorithmFactory.cpp + LinearRAOAlgorithm.cpp + RandomRAOAlgorithm.cpp + NoParamRAOAlgorithmFactory.cpp + RAOAlgorithmFactoryFactory.cpp +) + +add_library (ctarao SHARED + ${CTARAO_LIBRARY_SRCS}) + +install(TARGETS ctarao DESTINATION usr/${CMAKE_INSTALL_LIBDIR}) \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.cpp b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4562012ce0eba0c845b35fb7c4ba3cccbfbef84d --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.cpp @@ -0,0 +1,74 @@ +/* + * 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/>. + */ + +#include <list> + +#include "EnterpriseRAOAlgorithm.hpp" +#include "castor/tape/tapeserver/SCSI/Structures.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +EnterpriseRAOAlgorithm::EnterpriseRAOAlgorithm(castor::tape::tapeserver::drive::DriveInterface * drive, const uint64_t maxFilesSupported):m_drive(drive), m_maxFilesSupported(maxFilesSupported) { +} + +EnterpriseRAOAlgorithm::~EnterpriseRAOAlgorithm() { +} + +std::vector<uint64_t> EnterpriseRAOAlgorithm::performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob> >& jobs) { + std::vector<uint64_t> raoOrder; + uint64_t njobs = jobs.size(); + uint32_t block_size = 262144; + std::list<castor::tape::SCSI::Structures::RAO::blockLims> files; + for (uint32_t i = 0; i < njobs; i++) { + cta::RetrieveJob *job = jobs.at(i).get(); + castor::tape::SCSI::Structures::RAO::blockLims lims; + strncpy((char*)lims.fseq, std::to_string(i).c_str(), sizeof(i)); + lims.begin = job->selectedTapeFile().blockId; + lims.end = job->selectedTapeFile().blockId + 8 + + /* ceiling the number of blocks */ + ((job->archiveFile.fileSize + block_size - 1) / block_size); + + files.push_back(lims); + if ((files.size() == m_maxFilesSupported) || + ((i == njobs - 1) && (files.size() > 1))) { + /* We do a RAO query if: + * 1. the maximum number of files supported by the drive + * for RAO query has been reached + * 2. the end of the jobs list has been reached and there are at least + * 2 unordered files + */ + m_drive->queryRAO(files, m_maxFilesSupported); + + /* Add the RAO sorted files to the new list*/ + for (auto fit = files.begin(); fit != files.end(); fit++) { + uint64_t id = atoi((char*)fit->fseq); + raoOrder.push_back(id); + } + files.clear(); + } + } + for (auto fit = files.begin(); fit != files.end(); fit++) { + uint64_t id = atoi((char*)fit->fseq); + raoOrder.push_back(id); + } + files.clear(); + return raoOrder; +} + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.hpp b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..34c3a0c5bdc9c1d043f77ffa8a96841d82d0acf1 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithm.hpp @@ -0,0 +1,60 @@ +/* + * 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 "RAOAlgorithm.hpp" +#include "castor/tape/tapeserver/drive/DriveInterface.hpp" +#include "EnterpriseRAOAlgorithmFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +class EnterpriseRAOAlgorithmFactory; + +/** + * This class represents an EnterpriseRAOAlgorithm. + */ +class EnterpriseRAOAlgorithm : public RAOAlgorithm{ +public: + friend EnterpriseRAOAlgorithmFactory; + + virtual ~EnterpriseRAOAlgorithm(); + + /** + * Asks the Enteprise drive to perform a RAO query in order to get the RAO of the + * files represented by the jobs passed in parameter + * @param jobs the jobs representing the files we want to perform the RAO on + * @return the vector of the indexes of the jobs passed in parameters rearranged by the RAO query + */ + std::vector<uint64_t> performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob>> & jobs) override; + +private: + /** + * Constructs an EnterpriseRAOAlgorithm + * @param drive the drive in order to call its RAO via its DriveInterface + * @param maxFilesSupported the maximum number of files supported by the drive to perform the RAO + */ + EnterpriseRAOAlgorithm(castor::tape::tapeserver::drive::DriveInterface * drive, const uint64_t maxFilesSupported); + + //Interface to the drive + castor::tape::tapeserver::drive::DriveInterface * m_drive; + //Maximum number of files supported by the drive to perform the RAO + uint64_t m_maxFilesSupported; +}; + +}}}} diff --git a/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.cpp b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36359f5c1151427b4ab5d31ce113c7625a3a4eb0 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.cpp @@ -0,0 +1,36 @@ +/* + * 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/>. + */ + +#include "EnterpriseRAOAlgorithmFactory.hpp" +#include "EnterpriseRAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +EnterpriseRAOAlgorithmFactory::EnterpriseRAOAlgorithmFactory(castor::tape::tapeserver::drive::DriveInterface * drive, const uint64_t maxFilesSupported): +m_drive(drive), m_maxFilesSupported(maxFilesSupported) { +} + +EnterpriseRAOAlgorithmFactory::~EnterpriseRAOAlgorithmFactory() { +} + +std::unique_ptr<RAOAlgorithm> EnterpriseRAOAlgorithmFactory::createRAOAlgorithm() { + return std::unique_ptr<RAOAlgorithm>(new EnterpriseRAOAlgorithm(m_drive,m_maxFilesSupported)); +} + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.hpp b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..956a369994ef81848bf27292f3f2be4136264887 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/EnterpriseRAOAlgorithmFactory.hpp @@ -0,0 +1,48 @@ +/* + * 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 "RAOAlgorithmFactory.hpp" +#include "castor/tape/tapeserver/drive/DriveInterface.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * Factory of EnterpriseRAOAlgorithm. + */ +class EnterpriseRAOAlgorithmFactory : public RAOAlgorithmFactory{ +public: + /** + * Constructor of this factory + * @param drive the DriveInterface to perform a RAO query + * @param maxFilesSupported the maximum number of files the drive supports to perform a RAO query + */ + EnterpriseRAOAlgorithmFactory(castor::tape::tapeserver::drive::DriveInterface * drive, const uint64_t maxFilesSupported); + + /** + * Returns an Enteprise RAO Algorithm + */ + std::unique_ptr<RAOAlgorithm> createRAOAlgorithm() override; + virtual ~EnterpriseRAOAlgorithmFactory(); +private: + drive::DriveInterface * m_drive; + uint64_t m_maxFilesSupported; +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.cpp b/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..838e9cd0fbf0d39c1e655a2541483fdfd6e69db9 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.cpp @@ -0,0 +1,44 @@ +/* + * 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/>. + */ + +#include <algorithm> +#include <numeric> + +#include "LinearRAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +LinearRAOAlgorithm::LinearRAOAlgorithm() { +} + +LinearRAOAlgorithm::~LinearRAOAlgorithm() { +} + +std::vector<uint64_t> LinearRAOAlgorithm::performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob> >& jobs) { + std::vector<uint64_t> raoIndices(jobs.size()); + //Initialize the vector of indices + std::iota(raoIndices.begin(),raoIndices.end(),0); + //Sort the indices regarding the fseq of the jobs located in the vector passed in parameter + std::stable_sort(raoIndices.begin(),raoIndices.end(),[&jobs](const uint64_t index1, const uint64_t index2){ + return jobs[index1]->selectedTapeFile().fSeq < jobs[index2]->selectedTapeFile().fSeq; + }); + return raoIndices; +} + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.hpp b/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..82a8c3ef7d85085b090dd4621fcc2a4ae7627cf5 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/LinearRAOAlgorithm.hpp @@ -0,0 +1,49 @@ +/* + * 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 "RAOAlgorithm.hpp" +#include "NoParamRAOAlgorithmFactory.hpp" + + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +class NoParamRAOAlgorithmFactory; + +/** + * This class represents a LinearRAOAlgorithm + */ +class LinearRAOAlgorithm : public RAOAlgorithm { +public: + friend NoParamRAOAlgorithmFactory; + + /** + * This method will return the indexes of the jobs that are reoreded in a linear way (sorted by fseq ascendant) + * Example : if the fseqs of jobs in parameter are arranged like this [2, 3, 1, 4] the + * algorithm will return the following indexes vector : [2, 0, 1, 3] + * @param jobs the jobs to perform the linear RAO query + * @return the indexes of the jobs ordered by fseq ascendant + */ + std::vector<uint64_t> performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob> >& jobs) override; + virtual ~LinearRAOAlgorithm(); +private: + LinearRAOAlgorithm(); +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.cpp b/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4941d21ab6f0c29246643e5f223f6f0a7be81f82 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.cpp @@ -0,0 +1,51 @@ +/* + * 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/>. + */ + +#include "NoParamRAOAlgorithmFactory.hpp" +#include "LinearRAOAlgorithm.hpp" +#include "RandomRAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +NoParamRAOAlgorithmFactory::NoParamRAOAlgorithmFactory(const RAOConfig::RAOAlgorithmType & type) : m_type(type) { +} + +NoParamRAOAlgorithmFactory::~NoParamRAOAlgorithmFactory() { +} + +std::unique_ptr<RAOAlgorithm> NoParamRAOAlgorithmFactory::createRAOAlgorithm() { + std::unique_ptr<RAOAlgorithm> ret; + switch(m_type){ + case RAOConfig::linear:{ + ret.reset(new LinearRAOAlgorithm()); + break; + } + case RAOConfig::random:{ + ret.reset(new RandomRAOAlgorithm()); + break; + } + default: + { + throw cta::exception::Exception("In NoParamRAOAlgorithmFactory::createRAOAlgorithm(): unknown type of algorithm"); + } + } + return ret; +} + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.hpp b/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..dcf05324fa45aee7249a359edb8a44000e719e6b --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/NoParamRAOAlgorithmFactory.hpp @@ -0,0 +1,50 @@ +/* + * 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 "RAOConfig.hpp" +#include "RAOAlgorithmFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * This factory allows to instanciate RAO algorithm that do not need any + * parameter to work. E.G the linear algorithm just does a sort of the fseqs, + * it does not need any parameter. + */ +class NoParamRAOAlgorithmFactory : public RAOAlgorithmFactory { +public: + /** + * Constructor + * @param type the type given will be used by the createRAOAlgorithm() method + * to instanciate the correct algorithm regarding its type + */ + NoParamRAOAlgorithmFactory(const RAOConfig::RAOAlgorithmType & type); + /** + * Returns the correct instance of RAO algorithm regarding the type + * given while constructing this factory. + * @throws Exception if the type is unknown + */ + std::unique_ptr<RAOAlgorithm> createRAOAlgorithm() override; + virtual ~NoParamRAOAlgorithmFactory(); +private: + RAOConfig::RAOAlgorithmType m_type; +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.cpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90494f273b6ffa9127e0fb7d3920123a6c6f2861 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.cpp @@ -0,0 +1,29 @@ +/* + * 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/>. + */ + +#include "RAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +RAOAlgorithm::RAOAlgorithm() { +} + +RAOAlgorithm::~RAOAlgorithm() { +} + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.hpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0c4e0fba9f680f910e09bf271283934316891592 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithm.hpp @@ -0,0 +1,46 @@ +/* + * 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 <vector> +#include <memory> +#include "scheduler/RetrieveJob.hpp" + + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * Abstract class that represents an RAO algorithm + */ +class RAOAlgorithm { +public: + RAOAlgorithm(); + virtual ~RAOAlgorithm(); + + /** + * Returns the vector of indexes of the jobs passed in parameter + * sorted according to an algorithm + * @param jobs the jobs to perform RAO on + * @return the vector of indexes sorted by an algorithm applied on the jobs passed in parameter + */ + virtual std::vector<uint64_t> performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob>> & jobs) = 0; + +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.cpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2cba088575c2036542243b33b2dc21b40a34a572 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.cpp @@ -0,0 +1,29 @@ +/* + * 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/>. + */ + + +#include "RAOAlgorithmFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + + + +RAOAlgorithmFactory::~RAOAlgorithmFactory() { +} + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.hpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e86a09379a9d840cecf987b6b22149973d5b3645 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactory.hpp @@ -0,0 +1,42 @@ +/* + * 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 "RAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * Abstract class that will be extended by subclasses in order + * to instanciate an RAOAlgorithm + */ +class RAOAlgorithmFactory { +public: + /** + * Creates an RAO algorithm that will be used to do a Recommended Access Order + * in order to give an optimized order to Retrieve files efficiently from a tape + * @return the RAO algorithm instance + */ + virtual std::unique_ptr<RAOAlgorithm> createRAOAlgorithm() = 0; + virtual ~RAOAlgorithmFactory(); +private: + +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.cpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b37e663f366d15a9534cad659c608c8f6b435625 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.cpp @@ -0,0 +1,71 @@ +/* + * 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/>. + */ + + +#include "RAOAlgorithmFactoryFactory.hpp" +#include "common/log/LogContext.hpp" +#include "EnterpriseRAOAlgorithmFactory.hpp" +#include "NoParamRAOAlgorithmFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +RAOAlgorithmFactoryFactory::RAOAlgorithmFactoryFactory(RAOManager & raoManager, cta::log::LogContext & lc):m_raoManager(raoManager), m_lc(lc) { +} + +std::unique_ptr<RAOAlgorithmFactory> RAOAlgorithmFactoryFactory::createAlgorithmFactory() { + std::unique_ptr<RAOAlgorithmFactory> ret; + auto maxFilesSupported = m_raoManager.getMaxFilesSupported(); + if(m_raoManager.isDriveEnterpriseEnabled()) { + if(m_raoManager.hasUDS() && maxFilesSupported){ + //We successfully queried the max limits UDS of the drive, we then return an Enterprise RAO factory + ret.reset(new EnterpriseRAOAlgorithmFactory(m_raoManager.getDrive(),maxFilesSupported.value())); + } + } else { + //We will instanciate a CTA RAO algorithm + RAOConfig::RAOAlgorithmType raoAlgoType; + try { + raoAlgoType = m_raoManager.getConfig().getAlgorithmType(); + } catch (const cta::exception::Exception & ex) { + //We failed to determine the RAOAlgorithmType, we use the linear algorithm by default + //log a warning + std::string msg = "In RAOAlgorithmFactoryFactory::createAlgorithmFactory(), unable to determine the RAO algorithm to use, the algorithm name provided" + " in the tapeserver configuration is " + m_raoManager.getConfig().getRAOAlgorithmName() + " the available algorithm names are " + m_raoManager.getConfig().getCTARAOAlgorithmNameAvailable() + + ". We will apply a linear algorithm instead."; + m_lc.log(cta::log::WARNING, msg); + raoAlgoType = RAOConfig::RAOAlgorithmType::linear; + } + switch(raoAlgoType){ + case RAOConfig::RAOAlgorithmType::linear: + case RAOConfig::RAOAlgorithmType::random: + { + ret.reset(new NoParamRAOAlgorithmFactory(raoAlgoType)); + break; + } + case RAOConfig::RAOAlgorithmType::sltf: + default: + break; + } + } + return ret; +} + + +RAOAlgorithmFactoryFactory::~RAOAlgorithmFactoryFactory() { +} + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.hpp b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.hpp new file mode 100644 index 0000000000000000000000000000000000000000..8c02404319ee1f8a05409c9455ea2e829890b77c --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOAlgorithmFactoryFactory.hpp @@ -0,0 +1,53 @@ +/* + * 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 "common/log/LogContext.hpp" +#include "RAOManager.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * Factory of RAOAlgorithmFactory + * This is where the logic of instanciating the correct RAOAlgorithmFactory is implemented. + * + * This logic is the following: + * If we were able to query the drive User Data Segments (UDS) limits, then it means + * that the type of algorithm to instanciate will be an enterprise drive one (instanciate a EnteprpriseRAOAlgorithmFactory) + * + * If we were not able to query the drive UDS limits, then it means that we will use a CTA RAO algorithm : linear, random or sltf + * + * For implementation, see the implementation of the createAlgorithmFactory() method + */ +class RAOAlgorithmFactoryFactory { +public: + RAOAlgorithmFactoryFactory(RAOManager & raoManager, cta::log::LogContext & lc); + /** + * Returns the correct RAOAlgorithmFactory according to the informations + * stored in the RAO manager + * @return + */ + std::unique_ptr<RAOAlgorithmFactory> createAlgorithmFactory(); + virtual ~RAOAlgorithmFactoryFactory(); +private: + RAOManager & m_raoManager; + cta::log::LogContext & m_lc; +}; + +}}}} diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.cpp b/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e324b2af9ff6c1ee8d77b6bfbbffe45046de4380 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.cpp @@ -0,0 +1,75 @@ +/* + * 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/>. + */ + +#include "RAOConfig.hpp" +#include "common/exception/Exception.hpp" +#include "common/utils/utils.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +const std::map<std::string,RAOConfig::RAOAlgorithmType> RAOConfig::c_raoAlgoStringTypeMap = { + {"linear",RAOConfig::RAOAlgorithmType::linear}, + {"random",RAOConfig::RAOAlgorithmType::random}, + {"sltf",RAOConfig::RAOAlgorithmType::sltf} +}; + +RAOConfig::RAOConfig(){} + +RAOConfig::RAOConfig(const bool useRAO, const std::string& raoAlgorithmName, const std::string raoAlgorithmOptions):m_useRAO(useRAO), m_raoAlgorithmName(raoAlgorithmName), m_raoAlgorithmOptions(raoAlgorithmOptions) { + +} + +bool RAOConfig::useRAO() const { + return m_useRAO; +} + +std::string RAOConfig::getRAOAlgorithmName() const { + return m_raoAlgorithmName; +} + +std::string RAOConfig::getRAOAlgorithmOptions() const { + return m_raoAlgorithmOptions; +} + +void RAOConfig::disableRAO(){ + m_useRAO = false; +} + +RAOConfig::RAOAlgorithmType RAOConfig::getAlgorithmType() const { + try { + return c_raoAlgoStringTypeMap.at(m_raoAlgorithmName); + } catch (const std::out_of_range &){ + throw cta::exception::Exception("The algorithm name provided by the RAO configuration does not match any RAO algorithm type."); + } +} + +std::string RAOConfig::getCTARAOAlgorithmNameAvailable() const { + std::string ret; + for(auto & kv: c_raoAlgoStringTypeMap){ + ret += kv.first + " "; + } + if(ret.size()){ + //remove last space + ret.resize(ret.size()-1); + } + return ret; +} + + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.hpp b/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4c1f3987afb219a467b2bca3518ca11736889330 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOConfig.hpp @@ -0,0 +1,101 @@ +/* + * 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 "tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp" +#include "tapeserver/castor/tape/tapeserver/SCSI/Structures.hpp" +#include <memory> +#include <common/log/LogContext.hpp> +#include <vector> + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + + /** + * This class contains the configuration of the CTA RAO Algorithm + * It is initialized by the DataTransferSession and is filled from the configuration file of the tapeserver. + */ + class RAOConfig{ + public: + /** + * This enum represent the RAO algorithm type implemented + * by CTA + */ + enum RAOAlgorithmType { + linear, + random, + //Short Locate Time First + sltf + }; + + RAOConfig(); + + /** + * Construct an RAO config + * @param useRAO if set to true, the RAO will be enabled. If false, not enabled. + * @param raoAlgorithmName the RAO algorithm that will be executed when called + * @param raoAlgorithmOptions the options that could be passed to the RAO algorithm + */ + RAOConfig(const bool useRAO, const std::string & raoAlgorithmName, const std::string raoAlgorithmOptions); + + /** + * Returns true if RAO has to be used, false otherwise + */ + bool useRAO() const; + + /** + * Returns the RAO algorithm name of this configuration + */ + std::string getRAOAlgorithmName() const; + + /** + * Returns the RAO algorithm options of this configuration + * @return + */ + std::string getRAOAlgorithmOptions() const; + + /** + * Disable RAO from this configuration + */ + void disableRAO(); + + /** + * Returns RAOAlgorithmType object corresopnding to this configration's raoAlgorithmName + * @return the RAOAlgorithmType object corresopnding to this configration raoAlgorithmName + * @throws cta::exception::Exception in case the algorithm name does not match any RAOAlgorithmType + */ + RAOAlgorithmType getAlgorithmType() const; + + /** + * Returns the CTA RAO algorithm name that can be used + */ + std::string getCTARAOAlgorithmNameAvailable() const; + + private: + bool m_useRAO = false; + std::string m_raoAlgorithmName; + std::string m_raoAlgorithmOptions; + + /** + * Static map in order to match the string representing an algorithm name and its enum type + */ + static const std::map<std::string, RAOAlgorithmType> c_raoAlgoStringTypeMap; + }; + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOManager.cpp b/tapeserver/castor/tape/tapeserver/RAO/RAOManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..479c081a2e312097ea016ce6b13f94f24166c169 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOManager.cpp @@ -0,0 +1,105 @@ +/* + * 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/>. + */ + + +#include "RAOManager.hpp" +#include "EnterpriseRAOAlgorithm.hpp" +#include "EnterpriseRAOAlgorithmFactory.hpp" +#include "NoParamRAOAlgorithmFactory.hpp" +#include "RAOAlgorithmFactoryFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +RAOManager::RAOManager(){ + m_config.disableRAO(); +} + +RAOManager::RAOManager(const castor::tape::tapeserver::rao::RAOConfig & config, castor::tape::tapeserver::drive::DriveInterface * drive):m_config(config),m_drive(drive) { +} + +RAOManager::RAOManager(const RAOManager& manager){ + if(this != &manager){ + m_config = manager.m_config; + m_drive = manager.m_drive; + m_enterpriseRaoLimits = manager.m_enterpriseRaoLimits; + m_hasUDS = manager.m_hasUDS; + m_maxFilesSupported = manager.m_maxFilesSupported; + } +} + +RAOManager& RAOManager::operator=(const RAOManager& manager) { + if(this != &manager){ + m_config = manager.m_config; + m_drive = manager.m_drive; + m_enterpriseRaoLimits = manager.m_enterpriseRaoLimits; + m_hasUDS = manager.m_hasUDS; + m_maxFilesSupported = manager.m_maxFilesSupported; + } + return *this; +} + + +RAOManager::~RAOManager() { +} + +bool RAOManager::useRAO() const{ + return m_config.useRAO(); +} + +bool RAOManager::hasUDS() const { + return m_hasUDS; +} + +bool RAOManager::isDriveEnterpriseEnabled() const { + return m_isDriveEnterpriseEnabled; +} + + +castor::tape::tapeserver::drive::DriveInterface* RAOManager::getDrive() const { + return m_drive; +} + + +void RAOManager::disableRAO(){ + m_config.disableRAO(); +} + +void RAOManager::setEnterpriseRAOUdsLimits(const SCSI::Structures::RAO::udsLimits& raoLimits) { + m_enterpriseRaoLimits = raoLimits; + m_maxFilesSupported = raoLimits.maxSupported; + m_hasUDS = true; + m_isDriveEnterpriseEnabled = true; +} + +cta::optional<uint64_t> RAOManager::getMaxFilesSupported() const{ + return m_maxFilesSupported; +} + +RAOConfig RAOManager::getConfig() const { + return m_config; +} + + +std::vector<uint64_t> RAOManager::queryRAO(const std::vector<std::unique_ptr<cta::RetrieveJob>> & jobs, cta::log::LogContext & lc){ + RAOAlgorithmFactoryFactory raoAlgoFactoryFactory(*this,lc); + std::unique_ptr<RAOAlgorithm> raoAlgo = raoAlgoFactoryFactory.createAlgorithmFactory()->createRAOAlgorithm(); + return raoAlgo->performRAO(jobs); +} + + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RAOManager.hpp b/tapeserver/castor/tape/tapeserver/RAO/RAOManager.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0e8796a0122ef888903b8036fe351e58b44dd669 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RAOManager.hpp @@ -0,0 +1,131 @@ +/* + * 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 <vector> +#include <memory> +#include "castor/tape/tapeserver/RAO/RAOConfig.hpp" +#include "castor/tape/tapeserver/drive/DriveInterface.hpp" +#include "castor/tape/tapeserver/SCSI/Structures.hpp" +#include "scheduler/RetrieveJob.hpp" +#include "common/optional.hpp" +#include "RAOAlgorithmFactory.hpp" +#include "common/log/LogContext.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +/** + * This class will be used to manage everything that is linked to RAO. + * It centralizes all the RAO-related task that are executed during the + * RecallTaskInjector lifecycle. + */ +class RAOManager { +public: + /** + * Default constructor, disable the RAO + */ + RAOManager(); + + /** + * Copy constructor + * @param manager the RAOManager to copy + */ + RAOManager(const RAOManager & manager); + + /** + * Constructor of a RAO manager + * @param config the configuration of the RAO to manage + * @param drive the DriveInterface of the drive that is mounting + */ + RAOManager(const RAOConfig & config, castor::tape::tapeserver::drive::DriveInterface * drive); + + /** + * Assignment operator + * */ + RAOManager & operator=(const RAOManager & manager); + + /** + * Returns true if RAO will be used, false otherwise + */ + bool useRAO() const; + + /** + * Returns true if the manager has informations about the drive's User Data Segments limits to + * perform RAO for enteprise drive + */ + bool hasUDS() const; + + /** + * Returns true if the manager can ask for an Enterprise RAO Algorithm + * false otherwise + */ + bool isDriveEnterpriseEnabled() const; + + /** + * Returns the pointer to the interface of that is mounting + */ + castor::tape::tapeserver::drive::DriveInterface * getDrive() const; + + /** + * Returns the number of files that will be supported by the RAO algorithm + */ + cta::optional<uint64_t> getMaxFilesSupported() const; + + /** + * Returns the RAOConfig that is used by this RAOManager + */ + RAOConfig getConfig() const; + + /** + * Disable the RAO algorithm + */ + void disableRAO(); + + /** + * Set the enterprise RAO User Data Segments limits + * that will be used by this manager to perform the Enterprise RAO query on the drive + * @param raoLimits the enterprise RAO user data segments limits + */ + void setEnterpriseRAOUdsLimits(const SCSI::Structures::RAO::udsLimits & raoLimits); + + /** + * Query the RAO of the files passed in parameter + * @param jobs the vector of jobs to query the RAO + * @param lc the log context + * @return the vector with re-arranged indexes of the jobs passed in parameter + * It does not returns the fseqs, but a vector of indexes that will be used by the recall task injector to pick + * the correct job after RAO has been done + */ + std::vector<uint64_t> queryRAO(const std::vector<std::unique_ptr<cta::RetrieveJob>> & jobs, cta::log::LogContext & lc); + + virtual ~RAOManager(); + +private: + RAOConfig m_config; + /** Enterprise Drive-specific RAO parameters */ + SCSI::Structures::RAO::udsLimits m_enterpriseRaoLimits; + //Is true if the drive have been able to get the RAO UDS limits numbers + bool m_hasUDS = false; + //The maximum number of files that will be considered for RAO + cta::optional<uint64_t> m_maxFilesSupported; + //Pointer to the drive interface of the drive currently used by the tapeserver + castor::tape::tapeserver::drive::DriveInterface * m_drive; + bool m_isDriveEnterpriseEnabled = false; +}; + +}}}} diff --git a/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.cpp b/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44f3a5b5656a2debb7b85633bd281a53b0bb90dc --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.cpp @@ -0,0 +1,36 @@ +/* + * 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/>. + */ + +#include "RandomRAOAlgorithm.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +RandomRAOAlgorithm::RandomRAOAlgorithm() { +} + +std::vector<uint64_t> RandomRAOAlgorithm::performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob> >& jobs) { + std::vector<uint64_t> raoIndices(jobs.size()); + std::iota(raoIndices.begin(),raoIndices.end(),0); + std::random_shuffle(raoIndices.begin(), raoIndices.end()); + return raoIndices; +} + +RandomRAOAlgorithm::~RandomRAOAlgorithm() { +} + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.hpp b/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7b93be12ee3be06585890bdd086530181582db03 --- /dev/null +++ b/tapeserver/castor/tape/tapeserver/RAO/RandomRAOAlgorithm.hpp @@ -0,0 +1,46 @@ +/* + * 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 "RAOAlgorithm.hpp" +#include "NoParamRAOAlgorithmFactory.hpp" + +namespace castor { namespace tape { namespace tapeserver { namespace rao { + +class NoParamRAOAlgorithmFactory; + +/** + * This RAO Algorithm is a random one. The indexes of the jobs passed in parameter + * will be organized randomly + */ +class RandomRAOAlgorithm : public RAOAlgorithm{ +public: + friend NoParamRAOAlgorithmFactory; + /** + * Returns a randomly organized vector of the indexes of the jobs passed in parameter + * @param jobs the jobs to perform the random RAO on + */ + std::vector<uint64_t> performRAO(const std::vector<std::unique_ptr<cta::RetrieveJob> >& jobs) override; + + virtual ~RandomRAOAlgorithm(); +private: + RandomRAOAlgorithm(); +}; + +}}}} \ No newline at end of file diff --git a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt index aff6ac79437fe4309bf007c43e2af7772ffd4f9b..09fe5024d4177e1e4ff73c90d8f1102ca58f307f 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt +++ b/tapeserver/castor/tape/tapeserver/daemon/CMakeLists.txt @@ -81,7 +81,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) add_library(ctaTapeServerDaemon ${CTATAPESERVERDAEMON_LIBRARY_SRCS}) -target_link_libraries(ctaTapeServerDaemon ctamessages ctacommon ${PROTOBUF3_LIBRARIES} ctascheduler ctalegacymsg ctacatalogue TapeDrive) +target_link_libraries(ctaTapeServerDaemon ctamessages ctacommon ${PROTOBUF3_LIBRARIES} ctascheduler ctalegacymsg ctacatalogue TapeDrive ctarao) add_dependencies(ctaTapeServerDaemon ctamessagesprotobuf) include_directories(${PROTOBUF3_INCLUDE_DIRS}) diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp index d153d909d2beaa6c91c8cf97663f5c8712838612..db460aced0a294d7cff3757320ba08dd78f0668a 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferConfig.hpp @@ -119,9 +119,14 @@ struct DataTransferConfig { bool useRAO; /** - * The name of the raoAlgorithm to use + * The name of the RAO LTO algorithm to use */ - std::string raoAlgorithm; + std::string raoLtoAlgorithm; + + /** + * The options that can be used by the raoAlgorithm + */ + std::string raoLtoAlgorithmOptions; /** * The path to the operator provided encyption control script (or empty string) diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp index 74fe8be20fd7338ec10728003a19f3ff6e98ad17..dc97c238615b62ad667f47fd777c42ac09e672cd 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSession.cpp @@ -39,6 +39,7 @@ #include "castor/tape/tapeserver/SCSI/Device.hpp" #include "common/exception/Exception.hpp" #include "scheduler/RetrieveMount.hpp" +#include "castor/tape/tapeserver/RAO/RAOConfig.hpp" #include <google/protobuf/stubs/common.h> #include <memory> @@ -272,7 +273,9 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction // The RecallTaskInjector and the TapeReadSingleThread share the promise if (m_castorConf.useRAO) { - rti.initRAO(m_castorConf.raoAlgorithm); + //castor::tape::tapeserver::rao::RAOConfig config; + castor::tape::tapeserver::rao::RAOConfig config(true, m_castorConf.raoLtoAlgorithm, m_castorConf.raoLtoAlgorithmOptions); + rti.initRAO(config); } bool noFilesToRecall = false; if (rti.synchronousFetch(noFilesToRecall)) { //adapt the recall task injector (starting from synchronousFetch) diff --git a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp index 99b8e5e428b108480f9771b47a475956c6aaf21c..7d00ace863a5da0d5b2215632f4101ea73124af3 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/DataTransferSessionTest.cpp @@ -319,6 +319,30 @@ public: mediaType.comment = "comment"; catalogue.createMediaType(s_adminOnAdminHost,mediaType); } + + /** + * Returns the map of Fseqs given by RAO from a string containing CTA logs + * @param log the string containing the CTA logs + * @return the map that gives for each RAO call, the associated ordered Fseqs according to the RAO algorithm result + */ + std::map<size_t, std::vector<std::string>> getRAOFseqs(const std::string & log){ + std::map<size_t,std::vector<std::string>> ret; + std::string logCopy = log; + std::string recallRAOOrderMsg = "Recall order of FSEQs using RAO: "; + size_t recallRAOOrderMsgSize = recallRAOOrderMsg.size(); + size_t posRAOMsg = logCopy.find(recallRAOOrderMsg); + size_t i = 0; + while(posRAOMsg != std::string::npos){ + size_t posFirstFseq = posRAOMsg + recallRAOOrderMsgSize; + size_t posLastFseq = logCopy.find("\"",posFirstFseq); + std::string stringFseq = logCopy.substr(posFirstFseq,posLastFseq - posFirstFseq); + cta::utils::splitString(stringFseq,' ',ret[i]); + logCopy = logCopy.substr(posLastFseq); + posRAOMsg = logCopy.find(recallRAOOrderMsg); + i++; + } + return ret; + } private: @@ -820,9 +844,8 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { int MAX_RECALLS = 50; int MAX_BULK_RECALLS = 31; - std::vector<int> expectedOrder; - std::vector<std::string> expectedFseqOrderLog; - + std::map<size_t,std::vector<std::string>> expectedRAOFseqOrder; + //RAO for the fake drive is a std::reverse // 6) Prepare files for reading by writing them to the mock system { // Label the tape @@ -842,6 +865,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { castor::tape::SCSI::Structures::zeroStruct(&data); int fseq; for (fseq=1; fseq <= MAX_RECALLS ; fseq ++) { + expectedRAOFseqOrder[fseq / MAX_BULK_RECALLS].push_back(std::to_string(fseq)); // Create a path to a remote destination file std::ostringstream remoteFilePath; remoteFilePath << "file://" << m_tmpDir << "/test" << fseq; @@ -891,38 +915,205 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { std::list<std::string> archiveFilePaths; scheduler.queueRetrieve(diskInstance, rReq, logContext); - expectedOrder.push_back(fseq); + } + } + //As RAO with the fakedrive is a std::reverse of the vector of the files given in parameter, + //we reverse all expected fseqs vectors + std::reverse(expectedRAOFseqOrder[0].begin(),expectedRAOFseqOrder[0].end()); + std::reverse(expectedRAOFseqOrder[1].begin(),expectedRAOFseqOrder[1].end()); + scheduler.waitSchedulerDbSubthreadsComplete(); + + // 6) Report the drive's existence and put it up in the drive register. + cta::tape::daemon::TpconfigLine driveConfig("T10D6116", "TestLogicalLibrary", "/dev/tape_T10D6116", "manual"); + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName=driveConfig.unitName; + driveInfo.logicalLibrary=driveConfig.rawLibrarySlot; + // We need to create the drive in the registry before being able to put it up. + scheduler.reportDriveStatus(driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, logContext); + cta::common::dataStructures::DesiredDriveState driveState; + driveState.up = true; + driveState.forceDown = false; + scheduler.setDesiredDriveState(s_adminOnAdminHost, driveConfig.unitName, driveState, logContext); - bool apply_rao = false; - bool add_expected = false; - if (MAX_BULK_RECALLS < 2) { - if (expectedOrder.size() % MAX_BULK_RECALLS == 0 || - fseq % MAX_RECALLS == 0) { - add_expected = true; - } - } - else if (MAX_BULK_RECALLS >= 30) { - if ((expectedOrder.size() % 30 == 0) || - (fseq % MAX_RECALLS == 0) || (fseq % MAX_BULK_RECALLS == 0)) { - apply_rao = true; - add_expected = true; - } - } - else if ((fseq % MAX_BULK_RECALLS == 0) || (fseq % MAX_RECALLS == 0)) { - apply_rao = true; - add_expected = true; - } - if (apply_rao) { - std::reverse(expectedOrder.begin(), expectedOrder.end()); - } - if (add_expected) { - std::stringstream expectedLogLine; - for(const auto &fseq: expectedOrder) { - expectedLogLine << " " << fseq; - } - expectedFseqOrderLog.push_back(expectedLogLine.str()); - expectedOrder.clear(); - } + // 7) Create the data transfer session + DataTransferConfig castorConf; + castorConf.bufsz = 1024*1024; // 1 MB memory buffers + castorConf.nbBufs = 10; + castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000; + castorConf.bulkRequestRecallMaxFiles = MAX_BULK_RECALLS - 1; + castorConf.nbDiskThreads = 1; + castorConf.useRAO = true; + cta::log::DummyLogger dummyLog("dummy", "dummy"); + cta::mediachanger::MediaChangerFacade mc(dummyLog); + cta::server::ProcessCap capUtils; + castor::messages::TapeserverProxyDummy initialProcess; + castor::tape::tapeserver::daemon::DataTransferSession sess("tapeHost", logger, mockSys, + driveConfig, mc, initialProcess, capUtils, castorConf, scheduler); + + // 8) Run the data transfer session + sess.execute(); + + // 9) Check the session git the correct VID + ASSERT_EQ(s_vid, sess.getVid()); + + // 10) Check the remote files exist and have the correct size + for(auto & path: remoteFilePaths) { + struct stat statBuf; + bzero(&statBuf, sizeof(statBuf)); + const int statRc = stat(path.substr(7).c_str(), &statBuf); //remove the "file://" for stat-ing + ASSERT_EQ(0, statRc); + ASSERT_EQ(1000, statBuf.st_size); //same size of data + } + + // 10) Check logs + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" serialNumber=\"123456\" " + "mountTotalCorrectedReadErrors=\"5\" mountTotalReadBytesProcessed=\"4096\" " + "mountTotalUncorrectedReadErrors=\"1\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" serialNumber=\"123456\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); + + ASSERT_EQ(expectedRAOFseqOrder,getRAOFseqs(logToCheck)); +} + +TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallLinearAlgorithm) { + // 0) Prepare the logger for everyone + cta::log::StringLogger logger("dummy","tapeServerUnitTest",cta::log::DEBUG); + cta::log::LogContext logContext(logger); + + setupDefaultCatalogue(); + // 1) prepare the fake scheduler + std::string vid = s_vid; + // cta::MountType::Enum mountType = cta::MountType::RETRIEVE; + + // 3) Prepare the necessary environment (logger, plus system wrapper), + castor::tape::System::mockWrapper mockSys; + mockSys.delegateToFake(); + mockSys.disableGMockCallsCounting(); + mockSys.fake.setupForVirtualDriveSLC6(); + //delete is unnecessary + //pointer with ownership will be passed to the application, + //which will do the delete + mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeNonRAODrive; + + // 4) Create the scheduler + auto & catalogue = getCatalogue(); + auto & scheduler = getScheduler(); + + // Always use the same requester + const cta::common::dataStructures::SecurityIdentity requester; + + // List to remember the path of each remote file so that the existance of the + // files can be tested for at the end of the test + std::list<std::string> remoteFilePaths; + + // 5) Create the environment for the migration to happen (library + tape) + const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + libraryIsDisabled, libraryComment); + { + auto libraries = catalogue.getLogicalLibraries(); + ASSERT_EQ(1, libraries.size()); + ASSERT_EQ(s_libraryName, libraries.front().name); + ASSERT_EQ(libraryComment, libraries.front().comment); + } + const std::string tapeComment = "Tape comment"; + bool notDisabled = false; + bool notFull = false; + bool notReadOnly = false; + + { + cta::catalogue::CreateTapeAttributes tape; + tape.vid = s_vid; + tape.mediaType = s_mediaType; + tape.vendor = s_vendor; + tape.logicalLibraryName = s_libraryName; + tape.tapePoolName = s_tapePoolName; + tape.full = notFull; + tape.disabled = notDisabled; + tape.readOnly = notReadOnly; + tape.comment = tapeComment; + catalogue.createTape(s_adminOnAdminHost, tape); + } + + int MAX_RECALLS = 50; + int MAX_BULK_RECALLS = 31; + std::map<size_t,std::vector<std::string>> expectedRAOOrder; + // 6) Prepare files for reading by writing them to the mock system + { + // Label the tape + castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], + s_vid, false); + mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); + // And write to it + castor::tape::tapeserver::daemon::VolumeInfo volInfo; + volInfo.vid=s_vid; + castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"], + volInfo , 0, true, false); + + // Write a few files on the virtual tape and modify the archive name space + // so that it is in sync + uint8_t data[1000]; + size_t archiveFileSize=sizeof(data); + castor::tape::SCSI::Structures::zeroStruct(&data); + int fseq; + //For the RAO orders we will have two rao calls : first with 30 files, + //the second with 20 files + for (fseq=1; fseq <= MAX_RECALLS ; fseq ++) { + expectedRAOOrder[fseq / MAX_BULK_RECALLS].push_back(std::to_string(fseq)); + // Create a path to a remote destination file + std::ostringstream remoteFilePath; + remoteFilePath << "file://" << m_tmpDir << "/test" << fseq; + remoteFilePaths.push_back(remoteFilePath.str()); + + // Create an archive file entry in the archive namespace + auto tapeFileWrittenUP = cta::make_unique<cta::catalogue::TapeFileWritten>(); + auto &tapeFileWritten=*tapeFileWrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> tapeFileWrittenSet; + tapeFileWrittenSet.insert(tapeFileWrittenUP.release()); + + // Write the file to tape + cta::MockArchiveMount mam(catalogue); + std::unique_ptr<cta::ArchiveJob> aj(new cta::MockArchiveJob(&mam, catalogue)); + aj->tapeFile.fSeq = fseq; + aj->archiveFile.archiveFileID = fseq; + castor::tape::tapeFile::WriteFile wf(&ws, *aj, archiveFileSize); + tapeFileWritten.blockId = wf.getBlockId(); + // Write the data (one block) + wf.write(data, archiveFileSize); + // Close the file + wf.close(); + + // Create file entry in the archive namespace + tapeFileWritten.archiveFileId=fseq; + tapeFileWritten.checksumBlob.insert(cta::checksum::ADLER32, cta::utils::getAdler32(data, archiveFileSize)); + tapeFileWritten.vid=volInfo.vid; + tapeFileWritten.size=archiveFileSize; + tapeFileWritten.fSeq=fseq; + tapeFileWritten.copyNb=1; + tapeFileWritten.diskInstance = s_diskInstance; + tapeFileWritten.diskFileId = fseq; + + tapeFileWritten.diskFileOwnerUid = DISK_FILE_SOME_USER; + tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; + tapeFileWritten.storageClassName = s_storageClassName; + tapeFileWritten.tapeDrive = "drive0"; + catalogue.filesWrittenToTape(tapeFileWrittenSet); + + // Schedule the retrieval of the file + std::string diskInstance="disk_instance"; + cta::common::dataStructures::RetrieveRequest rReq; + rReq.archiveFileID=fseq; + rReq.requester.name = s_userName; + rReq.requester.group = "someGroup"; + rReq.dstURL = remoteFilePaths.back(); + std::list<std::string> archiveFilePaths; + scheduler.queueRetrieve(diskInstance, rReq, logContext); } } scheduler.waitSchedulerDbSubthreadsComplete(); @@ -947,6 +1138,7 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { castorConf.bulkRequestRecallMaxFiles = MAX_BULK_RECALLS - 1; castorConf.nbDiskThreads = 1; castorConf.useRAO = true; + castorConf.raoLtoAlgorithm = "linear"; cta::log::DummyLogger dummyLog("dummy", "dummy"); cta::mediachanger::MediaChangerFacade mc(dummyLog); cta::server::ProcessCap capUtils; @@ -980,9 +1172,206 @@ TEST_P(DataTransferSessionTest, DataTransferSessionRAORecall) { "mountReadTransients=\"10\" " "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); - for (std::string s : expectedFseqOrderLog) { - ASSERT_NE(std::string::npos, logToCheck.find(s)); + + ASSERT_EQ(expectedRAOOrder,getRAOFseqs(logToCheck)); +} + +TEST_P(DataTransferSessionTest, DataTransferSessionRAORecallRAOAlgoDoesNotExistShouldApplyLinear) { + // 0) Prepare the logger for everyone + cta::log::StringLogger logger("dummy","tapeServerUnitTest",cta::log::DEBUG); + cta::log::LogContext logContext(logger); + + setupDefaultCatalogue(); + // 1) prepare the fake scheduler + std::string vid = s_vid; + // cta::MountType::Enum mountType = cta::MountType::RETRIEVE; + + // 3) Prepare the necessary environment (logger, plus system wrapper), + castor::tape::System::mockWrapper mockSys; + mockSys.delegateToFake(); + mockSys.disableGMockCallsCounting(); + mockSys.fake.setupForVirtualDriveSLC6(); + //delete is unnecessary + //pointer with ownership will be passed to the application, + //which will do the delete + mockSys.fake.m_pathToDrive["/dev/nst0"] = new castor::tape::tapeserver::drive::FakeNonRAODrive; + + // 4) Create the scheduler + auto & catalogue = getCatalogue(); + auto & scheduler = getScheduler(); + + // Always use the same requester + const cta::common::dataStructures::SecurityIdentity requester; + + // List to remember the path of each remote file so that the existance of the + // files can be tested for at the end of the test + std::list<std::string> remoteFilePaths; + + // 5) Create the environment for the migration to happen (library + tape) + const std::string libraryComment = "Library comment"; + const bool libraryIsDisabled = false; + catalogue.createLogicalLibrary(s_adminOnAdminHost, s_libraryName, + libraryIsDisabled, libraryComment); + { + auto libraries = catalogue.getLogicalLibraries(); + ASSERT_EQ(1, libraries.size()); + ASSERT_EQ(s_libraryName, libraries.front().name); + ASSERT_EQ(libraryComment, libraries.front().comment); + } + const std::string tapeComment = "Tape comment"; + bool notDisabled = false; + bool notFull = false; + bool notReadOnly = false; + + { + cta::catalogue::CreateTapeAttributes tape; + tape.vid = s_vid; + tape.mediaType = s_mediaType; + tape.vendor = s_vendor; + tape.logicalLibraryName = s_libraryName; + tape.tapePoolName = s_tapePoolName; + tape.full = notFull; + tape.disabled = notDisabled; + tape.readOnly = notReadOnly; + tape.comment = tapeComment; + catalogue.createTape(s_adminOnAdminHost, tape); } + + int MAX_RECALLS = 50; + int MAX_BULK_RECALLS = 31; + std::map<size_t,std::vector<std::string>> expectedRAOOrder; + // 6) Prepare files for reading by writing them to the mock system + { + // Label the tape + castor::tape::tapeFile::LabelSession ls(*mockSys.fake.m_pathToDrive["/dev/nst0"], + s_vid, false); + mockSys.fake.m_pathToDrive["/dev/nst0"]->rewind(); + // And write to it + castor::tape::tapeserver::daemon::VolumeInfo volInfo; + volInfo.vid=s_vid; + castor::tape::tapeFile::WriteSession ws(*mockSys.fake.m_pathToDrive["/dev/nst0"], + volInfo , 0, true, false); + + // Write a few files on the virtual tape and modify the archive name space + // so that it is in sync + uint8_t data[1000]; + size_t archiveFileSize=sizeof(data); + castor::tape::SCSI::Structures::zeroStruct(&data); + int fseq; + //For the RAO orders we will have two rao calls : first with 30 files, + //the second with 20 files + for (fseq=1; fseq <= MAX_RECALLS ; fseq ++) { + expectedRAOOrder[fseq / MAX_BULK_RECALLS].push_back(std::to_string(fseq)); + // Create a path to a remote destination file + std::ostringstream remoteFilePath; + remoteFilePath << "file://" << m_tmpDir << "/test" << fseq; + remoteFilePaths.push_back(remoteFilePath.str()); + + // Create an archive file entry in the archive namespace + auto tapeFileWrittenUP = cta::make_unique<cta::catalogue::TapeFileWritten>(); + auto &tapeFileWritten=*tapeFileWrittenUP; + std::set<cta::catalogue::TapeItemWrittenPointer> tapeFileWrittenSet; + tapeFileWrittenSet.insert(tapeFileWrittenUP.release()); + + // Write the file to tape + cta::MockArchiveMount mam(catalogue); + std::unique_ptr<cta::ArchiveJob> aj(new cta::MockArchiveJob(&mam, catalogue)); + aj->tapeFile.fSeq = fseq; + aj->archiveFile.archiveFileID = fseq; + castor::tape::tapeFile::WriteFile wf(&ws, *aj, archiveFileSize); + tapeFileWritten.blockId = wf.getBlockId(); + // Write the data (one block) + wf.write(data, archiveFileSize); + // Close the file + wf.close(); + + // Create file entry in the archive namespace + tapeFileWritten.archiveFileId=fseq; + tapeFileWritten.checksumBlob.insert(cta::checksum::ADLER32, cta::utils::getAdler32(data, archiveFileSize)); + tapeFileWritten.vid=volInfo.vid; + tapeFileWritten.size=archiveFileSize; + tapeFileWritten.fSeq=fseq; + tapeFileWritten.copyNb=1; + tapeFileWritten.diskInstance = s_diskInstance; + tapeFileWritten.diskFileId = fseq; + + tapeFileWritten.diskFileOwnerUid = DISK_FILE_SOME_USER; + tapeFileWritten.diskFileGid = DISK_FILE_SOME_GROUP; + tapeFileWritten.storageClassName = s_storageClassName; + tapeFileWritten.tapeDrive = "drive0"; + catalogue.filesWrittenToTape(tapeFileWrittenSet); + + // Schedule the retrieval of the file + std::string diskInstance="disk_instance"; + cta::common::dataStructures::RetrieveRequest rReq; + rReq.archiveFileID=fseq; + rReq.requester.name = s_userName; + rReq.requester.group = "someGroup"; + rReq.dstURL = remoteFilePaths.back(); + std::list<std::string> archiveFilePaths; + scheduler.queueRetrieve(diskInstance, rReq, logContext); + } + } + scheduler.waitSchedulerDbSubthreadsComplete(); + + // 6) Report the drive's existence and put it up in the drive register. + cta::tape::daemon::TpconfigLine driveConfig("T10D6116", "TestLogicalLibrary", "/dev/tape_T10D6116", "manual"); + cta::common::dataStructures::DriveInfo driveInfo; + driveInfo.driveName=driveConfig.unitName; + driveInfo.logicalLibrary=driveConfig.rawLibrarySlot; + // We need to create the drive in the registry before being able to put it up. + scheduler.reportDriveStatus(driveInfo, cta::common::dataStructures::MountType::NoMount, cta::common::dataStructures::DriveStatus::Down, logContext); + cta::common::dataStructures::DesiredDriveState driveState; + driveState.up = true; + driveState.forceDown = false; + scheduler.setDesiredDriveState(s_adminOnAdminHost, driveConfig.unitName, driveState, logContext); + + // 7) Create the data transfer session + DataTransferConfig castorConf; + castorConf.bufsz = 1024*1024; // 1 MB memory buffers + castorConf.nbBufs = 10; + castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000; + castorConf.bulkRequestRecallMaxFiles = MAX_BULK_RECALLS - 1; + castorConf.nbDiskThreads = 1; + castorConf.useRAO = true; + castorConf.raoLtoAlgorithm = "DOES_NOT_EXIST"; + cta::log::DummyLogger dummyLog("dummy", "dummy"); + cta::mediachanger::MediaChangerFacade mc(dummyLog); + cta::server::ProcessCap capUtils; + castor::messages::TapeserverProxyDummy initialProcess; + castor::tape::tapeserver::daemon::DataTransferSession sess("tapeHost", logger, mockSys, + driveConfig, mc, initialProcess, capUtils, castorConf, scheduler); + + // 8) Run the data transfer session + sess.execute(); + + // 9) Check the session git the correct VID + ASSERT_EQ(s_vid, sess.getVid()); + + // 10) Check the remote files exist and have the correct size + for(auto & path: remoteFilePaths) { + struct stat statBuf; + bzero(&statBuf, sizeof(statBuf)); + const int statRc = stat(path.substr(7).c_str(), &statBuf); //remove the "file://" for stat-ing + ASSERT_EQ(0, statRc); + ASSERT_EQ(1000, statBuf.st_size); //same size of data + } + + // 10) Check logs + std::string logToCheck = logger.getLog(); + logToCheck += ""; + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" serialNumber=\"123456\" " + "mountTotalCorrectedReadErrors=\"5\" mountTotalReadBytesProcessed=\"4096\" " + "mountTotalUncorrectedReadErrors=\"1\" mountTotalNonMediumErrorCounts=\"2\"")); + ASSERT_NE(std::string::npos, logToCheck.find("firmwareVersion=\"123A\" serialNumber=\"123456\" lifetimeMediumEfficiencyPrct=\"100\" " + "mountReadEfficiencyPrct=\"100\" mountWriteEfficiencyPrct=\"100\" " + "mountReadTransients=\"10\" " + "mountServoTemps=\"10\" mountServoTransients=\"5\" mountTemps=\"100\" " + "mountTotalReadRetries=\"25\" mountTotalWriteRetries=\"25\" mountWriteTransients=\"10\"")); + + ASSERT_NE(std::string::npos, logToCheck.find("In RAOAlgorithmFactoryFactory::createAlgorithmFactory(), unable to determine the RAO algorithm to use")); + + ASSERT_EQ(expectedRAOOrder,getRAOFseqs(logToCheck)); } TEST_P(DataTransferSessionTest, DataTransferSessionNoSuchDrive) { diff --git a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.cpp b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.cpp index 76b05d54ffeca3064b4ef6a7e0a26b67ef1c75ec..4da74d9ff00a90aa26a41885f6bb4ad31da45052 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.cpp +++ b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.cpp @@ -30,6 +30,7 @@ #include "castor/tape/tapeserver/SCSI/Structures.hpp" #include "castor/tape/tapeserver/drive/DriveInterface.hpp" #include "scheduler/RetrieveJob.hpp" +#include "castor/tape/tapeserver/drive/DriveGeneric.hpp" #include <stdint.h> @@ -49,7 +50,6 @@ RecallTaskInjector::RecallTaskInjector(RecallMemoryManager & mm, m_thread(*this),m_memManager(mm), m_tapeReader(tapeReader),m_diskWriter(diskWriter), m_retrieveMount(retrieveMount),m_lc(lc),m_maxFiles(maxFiles),m_maxBytes(byteSizeThreshold), - m_useRAO(false), m_firstTasksInjectedFuture(m_firstTasksInjectedPromise.get_future()){} //------------------------------------------------------------------------------ //destructor @@ -93,9 +93,8 @@ void RecallTaskInjector::setDriveInterface(castor::tape::tapeserver::drive::Driv //------------------------------------------------------------------------------ //initRAO //------------------------------------------------------------------------------ -void RecallTaskInjector::initRAO(const std::string & raoAlgorithm) { - m_useRAO = true; - m_raoAlgorithm = raoAlgorithm; +void RecallTaskInjector::initRAO(const castor::tape::tapeserver::rao::RAOConfig & config) { + this->m_raoManager = castor::tape::tapeserver::rao::RAOManager(config,m_drive); m_raoFuture = m_raoPromise.get_future(); } //------------------------------------------------------------------------------ @@ -141,63 +140,26 @@ void RecallTaskInjector::waitForFirstTasksInjectedPromise(){ //injectBulkRecalls //------------------------------------------------------------------------------ void RecallTaskInjector::injectBulkRecalls() { - - uint32_t block_size = 262144; uint32_t njobs = m_jobs.size(); - std::vector<uint32_t> raoOrder; + std::vector<uint64_t> raoOrder; - if (m_useRAO) { + bool useRAO = m_raoManager.useRAO(); + if (useRAO) { std::list<castor::tape::SCSI::Structures::RAO::blockLims> files; m_lc.log(cta::log::INFO, "Performing RAO reordering"); - - for (uint32_t i = 0; i < njobs; i++) { - cta::RetrieveJob *job = m_jobs.at(i).get(); - - castor::tape::SCSI::Structures::RAO::blockLims lims; - strncpy((char*)lims.fseq, std::to_string(i).c_str(), sizeof(i)); - lims.begin = job->selectedTapeFile().blockId; - lims.end = job->selectedTapeFile().blockId + 8 + - /* ceiling the number of blocks */ - ((job->archiveFile.fileSize + block_size - 1) / block_size); - - files.push_back(lims); - - if (files.size() == m_raoLimits.maxSupported || - ((i == njobs - 1) && (files.size() > 1))) { - /* We do a RAO query if: - * 1. the maximum number of files supported by the drive - * for RAO query has been reached - * 2. the end of the jobs list has been reached and there are at least - * 2 unordered files - */ - m_drive->queryRAO(files, m_raoLimits.maxSupported,m_raoAlgorithm); - - /* Add the RAO sorted files to the new list*/ - for (auto fit = files.begin(); fit != files.end(); fit++) { - uint64_t id = atoi((char*)fit->fseq); - raoOrder.push_back(id); - } - files.clear(); - } - } - /* Copy the rest of the files in the new ordered list */ - for (auto fit = files.begin(); fit != files.end(); fit++) { - uint64_t id = atoi((char*)fit->fseq); - raoOrder.push_back(id); - } - files.clear(); + raoOrder = m_raoManager.queryRAO(m_jobs,m_lc); } std::ostringstream recallOrderLog; - if(m_useRAO) { + if(useRAO) { recallOrderLog << "Recall order of FSEQs using RAO:"; } else { recallOrderLog << "Recall order of FSEQs:"; } for (uint32_t i = 0; i < njobs; i++) { - uint32_t index = m_useRAO ? raoOrder.at(i) : i; + uint64_t index = useRAO ? raoOrder.at(i) : i; cta::RetrieveJob *job = m_jobs.at(index).release(); recallOrderLog << " " << job->selectedTapeFile().fSeq; @@ -237,12 +199,12 @@ void RecallTaskInjector::injectBulkRecalls() { bool RecallTaskInjector::synchronousFetch(bool & noFilesToRecall) { noFilesToRecall = false; - uint64_t reqFiles = (m_useRAO && m_hasUDS) ? m_raoLimits.maxSupported - m_fetched : m_maxFiles; + uint64_t reqFiles = (m_raoManager.useRAO() && m_raoManager.getMaxFilesSupported()) ? m_raoManager.getMaxFilesSupported().value() - m_fetched : m_maxFiles; /* If RAO is enabled, we must ask for files up to 1PB. * We are limiting to 1PB because the size will be passed as * oracle::occi::Number which is limited to ~56 bits precision */ - uint64_t reqSize = (m_useRAO && m_hasUDS) ? 1024L * 1024 * 1024 * 1024 * 1024 : m_maxBytes; + uint64_t reqSize = (m_raoManager.useRAO() && m_raoManager.hasUDS()) ? 1024L * 1024 * 1024 * 1024 * 1024 : m_maxBytes; try { auto jobsList = m_retrieveMount.getNextJobBatch(reqFiles, reqSize, m_lc); for (auto & j: jobsList) @@ -266,7 +228,7 @@ bool RecallTaskInjector::synchronousFetch(bool & noFilesToRecall) return false; } else { - if (! m_useRAO) + if (! m_raoManager.useRAO()) injectBulkRecalls(); else { cta::log::ScopedParamContainer scoped(m_lc); @@ -302,34 +264,37 @@ void RecallTaskInjector::WorkerThread::run() using cta::log::LogContext; m_parent.m_lc.pushOrReplace(Param("thread", "RecallTaskInjector")); m_parent.m_lc.log(cta::log::DEBUG, "Starting RecallTaskInjector thread"); - if (m_parent.m_useRAO) { + if (m_parent.m_raoManager.useRAO()) { /* RecallTaskInjector is waiting to have access to the drive in order * to perform the RAO query; * This waitForPromise() call means that the drive is mounted */ m_parent.waitForPromise(); try { - m_parent.m_raoLimits = m_parent.m_drive->getLimitUDS(); - m_parent.m_hasUDS = true; - LogContext::ScopedParam sp(m_parent.m_lc, Param("maxSupportedUDS", m_parent.m_raoLimits.maxSupported)); - m_parent.m_lc.log(cta::log::INFO,"Query getLimitUDS for RAO completed"); - if (m_parent.m_fetched < m_parent.m_raoLimits.maxSupported) { - /* Fetching until we reach maxSupported for the tape drive RAO */ - bool noFilesToRecall; - m_parent.synchronousFetch(noFilesToRecall); - } - m_parent.injectBulkRecalls(); - /** - * Commenting this line as we want the RAO to be executed on - * all the batchs and not only one. - */ - //m_parent.m_useRAO = false; + m_parent.m_raoManager.setEnterpriseRAOUdsLimits(m_parent.m_drive->getLimitUDS()); + LogContext::ScopedParam sp(m_parent.m_lc, Param("maxSupportedUDS", m_parent.m_raoManager.getMaxFilesSupported().value())); + m_parent.m_lc.log(cta::log::INFO,"Query getLimitUDS for RAO Enterprise completed"); + } catch (castor::tape::SCSI::Exception& e) { + m_parent.m_raoManager.disableRAO(); + cta::log::ScopedParamContainer spc(m_parent.m_lc); + spc.add("exceptionMessage",e.getMessageValue()); + m_parent.m_lc.log(cta::log::ERR, "Error while fetching the limitUDS for RAO enterprise drive."); + } catch(const castor::tape::tapeserver::drive::DriveDoesNotSupportRAOException &ex){ + m_parent.m_lc.log(cta::log::INFO, "The drive does not support RAO Enterprise, will run a CTA RAO."); } - catch (castor::tape::SCSI::Exception& e) { - m_parent.m_lc.log(cta::log::WARNING, "The drive does not support RAO: disabled"); - m_parent.m_useRAO = false; - m_parent.injectBulkRecalls(); + cta::optional<uint64_t> maxFilesSupportedByRAO = m_parent.m_raoManager.getMaxFilesSupported(); + if (maxFilesSupportedByRAO && m_parent.m_fetched < maxFilesSupportedByRAO.value()) { + /* Fetching until we reach maxSupported for the tape drive RAO */ + //unused boolean here but need to be kept to respect the synchronousFetch signature + bool noFilesToRecall; + m_parent.synchronousFetch(noFilesToRecall); } + m_parent.injectBulkRecalls(); + /** + * Commenting this line as we want the RAO to be executed on + * all the batchs and not only one. + */ + //m_parent.m_raoManager.disableRAO(); } try{ while (1) { diff --git a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.hpp b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.hpp index 0157c9abae51d7e4096830927a2ab1a2160014a3..ade4ae5561c795b53bce16a63de5a17d8408273c 100644 --- a/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.hpp +++ b/tapeserver/castor/tape/tapeserver/daemon/RecallTaskInjector.hpp @@ -30,6 +30,8 @@ #include "scheduler/RetrieveJob.hpp" #include "scheduler/RetrieveMount.hpp" #include "castor/tape/tapeserver/drive/DriveInterface.hpp" +#include "castor/tape/tapeserver/RAO/RAOConfig.hpp" +#include "castor/tape/tapeserver/RAO/RAOManager.hpp" #include <future> @@ -122,7 +124,7 @@ public: /** * Initialize Recommended Access Order parameters */ - void initRAO(const std::string & raoAlgorithm); + void initRAO(const castor::tape::tapeserver::rao::RAOConfig & config); void waitForPromise(); @@ -229,23 +231,11 @@ private: //maximal number of cumulated byte requested. at once const uint64_t m_maxBytes; - - /** Flag indicating if the file recalls are performed using - * the Recommended Access Order (RAO) - */ - bool m_useRAO; /** - * The RAO algorithm to use, it is given by the tapeserver parameter - * RAOAlgorithm + * The RAO manager to perofrm RAO operations */ - std::string m_raoAlgorithm; - - /** Drive-specific RAO parameters */ - SCSI::Structures::RAO::udsLimits m_raoLimits; - - /** Indicator that UDS limits gave been obtained */ - bool m_hasUDS = false; + castor::tape::tapeserver::rao::RAOManager m_raoManager; /** Number of jobs to be fetched before the tape is mounted. * The desired number is m_raoLimits.maxSupported diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp index 7f9c81bd116a0962df451f836b3aec16e7ffded0..23ba2a409aaaaa500f50ed7b545a4e40ea8e489f 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.cpp @@ -156,7 +156,12 @@ std::vector<castor::tape::tapeserver::drive::endOfWrapPosition> drive::DriveLTO: return ret; } -void drive::DriveLTO::queryRAO(std::list<SCSI::Structures::RAO::blockLims>& files, int maxSupported, const std::string & raoAlgorithm) { +SCSI::Structures::RAO::udsLimits drive::DriveLTO::getLimitUDS() { + throw castor::tape::tapeserver::drive::DriveDoesNotSupportRAOException("Drive does not support RAO enterprise."); +} + + +void drive::DriveLTO::queryRAO(std::list<SCSI::Structures::RAO::blockLims>& files, int maxSupported) { //TODO : Create an interface RAOAlgorithm with a method called getRAO() taking the files list as input/output parameter //Implement this method in three different classes : LinearRAOAlgorithm, RandomRAOAlgorithm, CERNRAOAlgorithm (or another name) //Create a factory to return the correct implementation subclass regarding the raoAlgorithm string parameter. @@ -253,6 +258,7 @@ drive::deviceInfo drive::DriveMHVTL::getDeviceInfo() { } SCSI::Structures::RAO::udsLimits drive::DriveMHVTL::getLimitUDS(){ + throw drive::DriveDoesNotSupportRAOException("MHVTL does not support getLimitUDS"); SCSI::Structures::RAO::udsLimits lims; //For MHVTL and for tests, assume that //the max number of files for RAO supported by an MHVTL drive @@ -262,7 +268,7 @@ SCSI::Structures::RAO::udsLimits drive::DriveMHVTL::getLimitUDS(){ return lims; } -void drive::DriveMHVTL::queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & raoAlgorithm){ +void drive::DriveMHVTL::queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported){ //The query RAO method of MHVTL drive returns nothing //something could be implemented for testing... } @@ -972,7 +978,7 @@ void drive::DriveGeneric::receiveRAO(std::list<SCSI::Structures::RAO::blockLims> } void drive::DriveGeneric::queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, - int maxSupported, const std::string & raoAlgorithm) { + int maxSupported) { generateRAO(files, maxSupported); receiveRAO(files); } diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp index e6789636961bd2f983136e72c29f75899671adda..ef3c4a40d8805200d3affcaf6f14d42fcbea5389 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveGeneric.hpp @@ -28,6 +28,8 @@ namespace castor { namespace tape { namespace tapeserver { namespace drive { + + CTA_GENERATE_EXCEPTION_CLASS(DriveDoesNotSupportRAOException); /** * Class abstracting the tape drives. This class is templated to allow the use * of unrelated test harness and real system. The test harness is made up of @@ -479,11 +481,9 @@ namespace drive { * @param filename The name of the file containing the sequential order of * a list of files [line format: ID:BLOCK_START:BLOCK_END] * @param maxSupported, the max number of files the drive is able to perform an RAO on - * @param raoAlgorithm, the name of the RAO algorithm to use, if the specified name - * does not match any raoAlgorithm, the linear algorithm will be used. */ - virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & raoAlgorithm); - + virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported); + protected: SCSI::DeviceInfo m_SCSIInfo; int m_tapeFD; @@ -583,7 +583,7 @@ namespace drive { virtual std::map<std::string,uint32_t> getVolumeStats(); virtual drive::deviceInfo getDeviceInfo(); virtual SCSI::Structures::RAO::udsLimits getLimitUDS(); - virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & raoAlgorithm); + virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported); }; class DriveLTO : public DriveGeneric { @@ -595,8 +595,8 @@ namespace drive { virtual compressionStats getCompression(); virtual void clearCompressionStats(); virtual std::vector<castor::tape::tapeserver::drive::endOfWrapPosition> getEndOfWrapPositions(); - virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims>& files, int maxSupported, const std::string& raoAlgorithm); - + virtual SCSI::Structures::RAO::udsLimits getLimitUDS(); + virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims>& files, int maxSupported); }; class DriveIBM3592 : public DriveGeneric { diff --git a/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp b/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp index d231d106314d237b076864b27658acd112705169..a4fb31f7cd1f7ae3102f61a06f655c71af41539f 100644 --- a/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/DriveInterface.hpp @@ -273,8 +273,7 @@ namespace drive { virtual bool hasTapeInPlace() = 0; virtual SCSI::Structures::RAO::udsLimits getLimitUDS() = 0; - virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & raoAlgorithm) = 0; - + virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported) = 0; /** * The configuration of the tape drive as parsed from the TPCONFIG file. */ diff --git a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp index 58e244ace5e7acec060a9e4c1c81329cf1cd3a85..306fa5ea0372adf8809add96640260a0bdc305b4 100644 --- a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp +++ b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.cpp @@ -23,6 +23,7 @@ #include "castor/tape/tapeserver/drive/FakeDrive.hpp" #include "castor/tape/tapeserver/SCSI/Structures.hpp" +#include "DriveGeneric.hpp" #include <iostream> namespace { @@ -325,7 +326,7 @@ castor::tape::SCSI::Structures::RAO::udsLimits } void castor::tape::tapeserver::drive::FakeDrive::queryRAO( - std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported, const std::string & queryRAO) { + std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported) { files.reverse(); } @@ -387,3 +388,14 @@ std::map<std::string,uint32_t> castor::tape::tapeserver::drive::FakeDrive::getVo return std::map<std::string,uint32_t>(); } + +castor::tape::tapeserver::drive::FakeNonRAODrive::FakeNonRAODrive():FakeDrive() { + +} + +castor::tape::SCSI::Structures::RAO::udsLimits castor::tape::tapeserver::drive::FakeNonRAODrive::getLimitUDS() { + throw castor::tape::tapeserver::drive::DriveDoesNotSupportRAOException("UnitTests"); +} + + + diff --git a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp index 89ea6ca20c121db841c3e79d6636404702b3e0b2..586c46dddf659c4f5aacb7cc6d97caee19a79dae 100644 --- a/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp +++ b/tapeserver/castor/tape/tapeserver/drive/FakeDrive.hpp @@ -112,7 +112,13 @@ namespace drive { virtual lbpToUse getLbpToUse(); virtual bool hasTapeInPlace(); virtual castor::tape::SCSI::Structures::RAO::udsLimits getLimitUDS(); - virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported,const std::string & raoAlgorithm); + virtual void queryRAO(std::list<SCSI::Structures::RAO::blockLims> &files, int maxSupported); + }; + + class FakeNonRAODrive : public FakeDrive{ + public: + FakeNonRAODrive(); + virtual castor::tape::SCSI::Structures::RAO::udsLimits getLimitUDS(); }; }}}} diff --git a/tapeserver/castor/tape/tapeserver/file/BasicReadWriteTest.cpp b/tapeserver/castor/tape/tapeserver/file/BasicReadWriteTest.cpp index 83c310967a669980e1eddcfdd7958656b34b5e0b..12b63097edabc5889509ae00c5fa282858d2a446 100644 --- a/tapeserver/castor/tape/tapeserver/file/BasicReadWriteTest.cpp +++ b/tapeserver/castor/tape/tapeserver/file/BasicReadWriteTest.cpp @@ -260,7 +260,7 @@ int main (int argc, char *argv[]) throw -1; } castor::tape::SCSI::Structures::RAO::udsLimits limits = drive->getLimitUDS(); - drive->queryRAO(files, limits.maxSupported,""); + drive->queryRAO(files, limits.maxSupported); } } diff --git a/tapeserver/daemon/DriveHandler.cpp b/tapeserver/daemon/DriveHandler.cpp index 5e6cbd8b451628861de6fd797c053acf5b0e9495..f40cb3de17c0b5ea881fed7420e6ec16c7471315 100644 --- a/tapeserver/daemon/DriveHandler.cpp +++ b/tapeserver/daemon/DriveHandler.cpp @@ -1076,7 +1076,8 @@ int DriveHandler::runChild() { dataTransferConfig.nbDiskThreads = m_tapedConfig.nbDiskThreads.value(); dataTransferConfig.useLbp = true; dataTransferConfig.useRAO = m_tapedConfig.useRAO.value() == "yes" ? true : false; - dataTransferConfig.raoAlgorithm = m_tapedConfig.raoAlgorithm.value(); + dataTransferConfig.raoLtoAlgorithm = m_tapedConfig.raoLtoAlgorithm.value(); + dataTransferConfig.raoLtoAlgorithmOptions = m_tapedConfig.raoLtoOptions.value(); dataTransferConfig.xrootPrivateKey = ""; // Before launching, and if this is the first session since daemon start, we will @@ -1143,7 +1144,7 @@ int DriveHandler::runChild() { capUtils, dataTransferConfig, scheduler); - + auto ret = dataTransferSession.execute(); agentHeartbeat.stopAndWaitThread(); return ret; diff --git a/tapeserver/daemon/TapedConfiguration.cpp b/tapeserver/daemon/TapedConfiguration.cpp index 1eaf5f9cf3348023a3db3a95a494168465b98286..c23207ce107530d07c98d4caebfd77ace9a1848c 100644 --- a/tapeserver/daemon/TapedConfiguration.cpp +++ b/tapeserver/daemon/TapedConfiguration.cpp @@ -109,7 +109,8 @@ TapedConfiguration TapedConfiguration::createFromCtaConf( ret.nbDiskThreads.setFromConfigurationFile(cf, generalConfigPath); //RAO ret.useRAO.setFromConfigurationFile(cf, generalConfigPath); - ret.raoAlgorithm.setFromConfigurationFile(cf,generalConfigPath); + ret.raoLtoAlgorithm.setFromConfigurationFile(cf,generalConfigPath); + ret.raoLtoOptions.setFromConfigurationFile(cf,generalConfigPath); // Watchdog: parameters for timeouts in various situations. ret.wdIdleSessionTimer.setFromConfigurationFile(cf, generalConfigPath); ret.wdMountMaxSecs.setFromConfigurationFile(cf, generalConfigPath); diff --git a/tapeserver/daemon/TapedConfiguration.hpp b/tapeserver/daemon/TapedConfiguration.hpp index 13ab316063d3f09c8bf96fb69f268af68f106637..225a1a6015721c24ab76ac1385ab0ff471783ae1 100644 --- a/tapeserver/daemon/TapedConfiguration.hpp +++ b/tapeserver/daemon/TapedConfiguration.hpp @@ -97,8 +97,11 @@ struct TapedConfiguration { cta::SourcedParameter<std::string> useRAO{ "taped", "UseRAO", "no", "Compile time default"}; /// RAO type of algorithm - cta::SourcedParameter<std::string> raoAlgorithm{ - "taped", "RAOAlgorithm","linear","Compile time default"}; + cta::SourcedParameter<std::string> raoLtoAlgorithm{ + "taped", "RAOLTOAlgorithm","linear","Compile time default"}; + cta::SourcedParameter<std::string> raoLtoOptions { + "taped", "RAOLTOAlgorithmOptions","","Compile time default" + }; //---------------------------------------------------------------------------- // Watchdog: parameters for timeouts in various situations. //----------------------------------------------------------------------------