Commit afe79588 authored by Eric Cano's avatar Eric Cano
Browse files

First implementation of generic popping from a container.

The unit test is disabled as it does not pass yet.
Templated some structures to reflect imperfect similarities between inserting and popping.
parent 4a909584
......@@ -42,16 +42,20 @@ public:
typedef std::string ContainerAddress;
typedef std::string ElementAddress;
typedef std::string ContainerIdentifyer;
class Element {};
typedef std::list<std::unique_ptr<Element>> ElementMemoryContainer;
typedef std::list <Element *> ElementPointerContainer;
struct InsertedElement {
typedef std::list<InsertedElement> list;
};
typedef std::list<std::unique_ptr<InsertedElement>> ElementMemoryContainer;
typedef std::list <InsertedElement *> ElementPointerContainer;
class ElementDescriptor {};
typedef std::list<ElementDescriptor> ElementDescriptorContainer;
struct ElementOpFailure {
template <class Element>
struct OpFailure {
Element * element;
std::exception_ptr failure;
typedef std::list<OpFailure> list;
};
typedef std::list<ElementOpFailure> ElementOpFailureContainer;
class PoppedElementsSummary;
class PopCriteria {
......@@ -76,19 +80,26 @@ public:
PoppedElementsList elements;
PoppedElementsSummary summary;
};
typedef std::set<ElementAddress> ElementsToSkipSet;
CTA_GENERATE_EXCEPTION_CLASS(NoSuchContainer);
template <class Element>
static ElementAddress getElementAddress(const Element & e);
static void getLockedAndFetched(Container & cont, ScopedExclusiveLock & contLock, AgentReference & agRef, const ContainerIdentifyer & cId,
log::LogContext & lc);
static void getLockedAndFetchedNoCreate(Container & cont, ScopedExclusiveLock & contLock, const ContainerIdentifyer & cId,
log::LogContext & lc);
static void addReferencesAndCommit(Container & cont, ElementMemoryContainer & elemMemCont);
void removeReferencesAndCommit(Container & cont, ElementOpFailureContainer & elementsOpFailures);
void removeReferencesAndCommit(Container & cont, typename OpFailure<InsertedElement>::list & elementsOpFailures);
void removeReferencesAndCommit(Container & cont, std::list<ElementAddress>& elementAddressList);
static ElementPointerContainer switchElementsOwnership(ElementMemoryContainer & elemMemCont, const ContainerAddress & contAddress,
const ContainerAddress & previousOwnerAddress, log::LogContext & lc);
template <class Element>
static PoppedElementsSummary getElementSummary(const Element &);
static PoppedElementsBatch getPoppingElementsCandidates(Container & cont, PopCriteria & unfulfilledCriteria,
ElementsToSkipSet & elemtsToSkip, log::LogContext & lc);
};
template <class C>
......@@ -97,15 +108,14 @@ public:
ContainerAlgorithms(Backend & backend, AgentReference & agentReference):
m_backend(backend), m_agentReference(agentReference) {}
typedef typename ContainerTraits<C>::Element Element;
typedef typename ContainerTraits<C>::ElementMemoryContainer ElementMemoryContainer;
typedef typename ContainerTraits<C>::InsertedElement InsertedElement;
/** Reference objects in the container and then switch their ownership them. Objects
* are provided existing and owned by algorithm's agent. Returns a list of
* @returns list of elements for which the addition or ownership switch failed.
* @throws */
void referenceAndSwitchOwnership(const typename ContainerTraits<C>::ContainerIdentifyer & contId,
typename ContainerTraits<C>::ElementMemoryContainer & elements, log::LogContext & lc) {
typename ContainerTraits<C>::InsertedElement::list & elements, log::LogContext & lc) {
C cont(m_backend);
ScopedExclusiveLock contLock;
ContainerTraits<C>::getLockedAndFetched(cont, contLock, m_agentReference, contId, lc);
......@@ -143,50 +153,86 @@ public:
}
}
typename ContainerTraits<C>::PoppedElementsBatch popNextBatch(typename ContainerTraits<C>::ContainerIdentifyer & contId,
typename ContainerTraits<C>::PoppedElementsBatch popNextBatch(const typename ContainerTraits<C>::ContainerIdentifyer & contId,
typename ContainerTraits<C>::PopCriteria & popCriteria, log::LogContext & lc) {
// Prepare the return value
typename ContainerTraits<C>::PoppedElementsBatch ret;
typename ContainerTraits<C>::PopCriteria unfulfilledCriteria = popCriteria;
size_t iterationCount=0;
typename ContainerTraits<C>::ElementsToSkipSet elementsToSkip;
while (ret.summary < popCriteria) {
// Get a container if it exists
C cont(m_backend);
iterationCount++;
ScopedExclusiveLock contLock;
try {
typename ContainerTraits<C>::getLockedAndFetchedNoCreate(cont, contId, lc);
ContainerTraits<C>::getLockedAndFetchedNoCreate(cont, contLock, contId, lc);
} catch (typename ContainerTraits<C>::NoSuchContainer &) {
// We could not find a container to pop from: return what we have.
return ret;
}
// We have a container. Get candidate element list from it.
typename ContainerTraits<C>::PoppingElementsCandidateList candidateElements =
ContainerTraits<C>::getPoppingElementsCandidates(cont, unfulfilledCriteria, lc);
typename ContainerTraits<C>::PoppedElementsBatch candidateElements =
ContainerTraits<C>::getPoppingElementsCandidates(cont, unfulfilledCriteria, elementsToSkip, lc);
// Reference the candidates to our agent
std::list<typename ContainerTraits<C>::ElementAddress> candidateElementsAddresses;
for (auto & e: candidateElements) {
for (auto & e: candidateElements.elements) {
candidateElementsAddresses.emplace_back(ContainerTraits<C>::getElementAddress(e));
}
m_agentReference.addBatchToOwnership(candidateElementsAddresses, m_backend);
// We can now attempt to switch ownership of elements
auto failedOwnershipSwitchElements = ContainerTraits<C>::switchElementsOwnership(candidateElements,
m_agentReference.getAgentAddress(), cont.getAddressIfSet());
m_agentReference.getAgentAddress(), cont.getAddressIfSet(), lc);
if (failedOwnershipSwitchElements.empty()) {
// This is the easy (and most common case). Everything went through fine.
ContainerTraits<C>::removeReferencesAndCommit(candidateElementsAddresses);
// This is the easy case (and most common case). Everything went through fine.
ContainerTraits<C>::removeReferencesAndCommit(cont, candidateElementsAddresses);
contLock.release();
// All jobs are validated
ret.summary += candidateElements.summary;
unfulfilledCriteria -= candidateElements.summary;
ret.elements.insertBack(std::move(candidateElements.elements));
} else {
// For the failed files, we have to differentiate the not owned or not existing ones from other error cases.
// For the not owned, not existing and those successfully switched, we have to de reference them form the container.
// For other cases, we will leave the elements referenced in the container, as we cannot ensure de-referencing is safe.
std::set<typename ContainerTraits<C>::ElementAddress> elementsNotToDereferenceFromContainer;
std::set<typename ContainerTraits<C>::ElementAddress> elementsNotToReport;
std::list<typename ContainerTraits<C>::ElementAddress> elementsToDereferenceFromAgent;
for (auto &e: failedOwnershipSwitchElements) {
try {
throw e.failure;
} catch (Backend::NoSuchObject &) {}
catch (Backend::WrongPreviousOwner&) {}
} catch (Backend::NoSuchObject &) {
elementsToDereferenceFromAgent.push_back(ContainerTraits<C>::getElementAddress(*e.element));
elementsNotToReport.insert(ContainerTraits<C>::getElementAddress(*e.element));
} catch (Backend::WrongPreviousOwner &) {
elementsToDereferenceFromAgent.push_back(ContainerTraits<C>::getElementAddress(*e.element));
elementsNotToReport.insert(ContainerTraits<C>::getElementAddress(*e.element));
} catch (Backend::CouldNotUnlock&) {
// Do nothing, this element was indeed OK.
}
catch (...) {
// This is a different error, so we will leave the reference to the element in the container
elementsNotToDereferenceFromContainer.insert(ContainerTraits<C>::getElementAddress(*e.element));
elementsToDereferenceFromAgent.push_back(ContainerTraits<C>::getElementAddress(*e.element));
elementsNotToReport.insert(ContainerTraits<C>::getElementAddress(*e.element));
elementsToSkip.insert(ContainerTraits<C>::getElementAddress(*e.element));
}
}
// We are done with the sorting. Apply the decisions...
std::list<typename ContainerTraits<C>::ElementAddress> elementsToDereferenceFromContainer;
for (auto & e: candidateElements.elements) {
if (!elementsNotToDereferenceFromContainer.count(ContainerTraits<C>::getElementAddress(e))) {
elementsToDereferenceFromContainer.push_back(ContainerTraits<C>::getElementAddress(e));
}
}
ContainerTraits<C>::removeReferencesAndCommit(cont, elementsToDereferenceFromContainer);
contLock.release();
m_agentReference.removeBatchFromOwnership(elementsToDereferenceFromAgent, m_backend);
for (auto & e: candidateElements.elements) {
if (!elementsNotToReport.count(ContainerTraits<C>::getElementAddress(e))) {
ret.summary += ContainerTraits<C>::getElementSummary(e);
unfulfilledCriteria -= ContainerTraits<C>::getElementSummary(e);
ret.elements.insertBack(std::move(e));
}
}
}
......
......@@ -32,7 +32,7 @@
namespace unitTests {
TEST(ObjectStore, ArchiveQueueAlgorithms) {
TEST(ObjectStore, DISABLED_ArchiveQueueAlgorithms) {
using namespace cta::objectstore;
// We will need a log object
#ifdef STDOUT_LOGGING
......@@ -59,7 +59,7 @@ TEST(ObjectStore, ArchiveQueueAlgorithms) {
rel.release();
agent.initialize();
agent.insertAndRegisterSelf(lc);
ContainerAlgorithms<ArchiveQueue>::ElementMemoryContainer requests;
ContainerAlgorithms<ArchiveQueue>::InsertedElement::list requests;
for (size_t i=0; i<10; i++) {
std::string arAddr = agentRef.nextId("ArchiveRequest");
agentRef.addToOwnership(arAddr, be);
......@@ -76,7 +76,7 @@ TEST(ObjectStore, ArchiveQueueAlgorithms) {
aFile.diskInstance = "eoseos";
aFile.fileSize = 667;
aFile.storageClass = "sc";
requests.emplace_back(ContainerAlgorithms<ArchiveQueue>::Element{cta::make_unique<ArchiveRequest>(arAddr, be), 1, aFile, mp});
requests.emplace_back(ContainerAlgorithms<ArchiveQueue>::InsertedElement{cta::make_unique<ArchiveRequest>(arAddr, be), 1, aFile, mp});
auto & ar=*requests.back().archiveRequest;
auto copyNb = requests.back().copyNb;
ar.initialize();
......@@ -92,6 +92,12 @@ TEST(ObjectStore, ArchiveQueueAlgorithms) {
}
ContainerAlgorithms<ArchiveQueue> archiveAlgos(be, agentRef);
archiveAlgos.referenceAndSwitchOwnership("Tapepool", requests, lc);
// Now get the requests back
ContainerTraits<ArchiveQueue>::PopCriteria popCriteria;
popCriteria.bytes = 1000;
popCriteria.files = 100;
auto popedJobs = archiveAlgos.popNextBatch("Tapepool", popCriteria, lc);
ASSERT_EQ(popedJobs.summary.files, 10);
}
TEST(ObjectStore, RetrieveQueueAlgorithms) {
......@@ -121,7 +127,7 @@ TEST(ObjectStore, RetrieveQueueAlgorithms) {
rel.release();
agent.initialize();
agent.insertAndRegisterSelf(lc);
ContainerAlgorithms<RetrieveQueue>::ElementMemoryContainer requests;
ContainerAlgorithms<RetrieveQueue>::InsertedElement::list requests;
for (size_t i=0; i<10; i++) {
std::string rrAddr = agentRef.nextId("RetrieveRequest");
agentRef.addToOwnership(rrAddr, be);
......@@ -151,7 +157,7 @@ TEST(ObjectStore, RetrieveQueueAlgorithms) {
rqc.mountPolicy.maxDrivesAllowed = 1;
rqc.mountPolicy.retrieveMinRequestAge = 1;
rqc.mountPolicy.retrievePriority = 1;
requests.emplace_back(ContainerAlgorithms<RetrieveQueue>::Element{cta::make_unique<RetrieveRequest>(rrAddr, be), 1, i, 667, mp,
requests.emplace_back(ContainerAlgorithms<RetrieveQueue>::InsertedElement{cta::make_unique<RetrieveRequest>(rrAddr, be), 1, i, 667, mp,
serializers::RetrieveJobStatus::RJS_Pending});
auto & rr=*requests.back().retrieveRequest;
rr.initialize();
......
/*
* The CERN Tape Archive (CTA) project
* Copyright (C) 2015 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 "ArchiveQueueAlgorithms.hpp"
#include "common/Timer.hpp"
#include "common/make_unique.hpp"
namespace cta { namespace objectstore {
void ContainerTraits<ArchiveQueue>::getLockedAndFetched(Container& cont, ScopedExclusiveLock& aqL, AgentReference& agRef,
const ContainerIdentifyer& contId, log::LogContext& lc) {
Helpers::getLockedAndFetchedQueue<Container>(cont, aqL, agRef, contId, QueueType::LiveJobs, lc);
}
void ContainerTraits<ArchiveQueue>::addReferencesAndCommit(Container& cont, InsertedElement::list& elemMemCont,
AgentReference& agentRef, log::LogContext& lc) {
std::list<ArchiveQueue::JobToAdd> jobsToAdd;
for (auto & e: elemMemCont) {
ElementDescriptor jd;
jd.copyNb = e.copyNb;
jd.tapePool = cont.getTapePool();
jd.owner = cont.getAddressIfSet();
ArchiveRequest & ar = *e.archiveRequest;
jobsToAdd.push_back({jd, ar.getAddressIfSet(), e.archiveFile.archiveFileID, e.archiveFile.fileSize,
e.mountPolicy, time(nullptr)});
}
cont.addJobsAndCommit(jobsToAdd, agentRef, lc);
}
void ContainerTraits<ArchiveQueue>::removeReferencesAndCommit(Container& cont, OpFailure<InsertedElement>::list& elementsOpFailures) {
std::list<std::string> elementsToRemove;
for (auto & eof: elementsOpFailures) {
elementsToRemove.emplace_back(eof.element->archiveRequest->getAddressIfSet());
}
cont.removeJobsAndCommit(elementsToRemove);
}
void ContainerTraits<ArchiveQueue>::removeReferencesAndCommit(Container& cont, std::list<ElementAddress>& elementAddressList) {
cont.removeJobsAndCommit(elementAddressList);
}
auto ContainerTraits<ArchiveQueue>::switchElementsOwnership(InsertedElement::list& elemMemCont, const ContainerAddress& contAddress, const ContainerAddress& previousOwnerAddress, log::LogContext& lc) -> OpFailure<InsertedElement>::list {
std::list<std::unique_ptr<ArchiveRequest::AsyncJobOwnerUpdater>> updaters;
for (auto & e: elemMemCont) {
ArchiveRequest & ar = *e.archiveRequest;
auto copyNb = e.copyNb;
updaters.emplace_back(ar.asyncUpdateJobOwner(copyNb, contAddress, previousOwnerAddress));
}
auto u = updaters.begin();
auto e = elemMemCont.begin();
OpFailure<InsertedElement>::list ret;
while (e != elemMemCont.end()) {
try {
u->get()->wait();
} catch (...) {
ret.push_back(OpFailure<InsertedElement>());
ret.back().element = &(*e);
ret.back().failure = std::current_exception();
}
u++;
e++;
}
return ret;
}
void ContainerTraits<ArchiveQueue>::getLockedAndFetchedNoCreate(Container& cont, ScopedExclusiveLock& contLock,
const ContainerIdentifyer& cId, log::LogContext& lc) {
// Try and get access to a queue.
size_t attemptCount = 0;
retry:
objectstore::RootEntry re(cont.m_objectStore);
re.fetchNoLock();
std::string aqAddress;
auto aql = re.dumpArchiveQueues(QueueType::LiveJobs);
for (auto & aqp : aql) {
if (aqp.tapePool == cId)
aqAddress = aqp.address;
}
if (!aqAddress.size()) throw NoSuchContainer("In ContainerTraits<ArchiveQueue>::getLockedAndFetchedNoCreate(): no such archive queue");
// try and lock the archive queue. Any failure from here on means the end of the getting jobs.
objectstore::ArchiveQueue aq(aqAddress, cont.m_objectStore);
objectstore::ScopedExclusiveLock aqlock;
//findQueueTime += localFindQueueTime = t.secs(utils::Timer::resetCounter);
try {
aqlock.lock(aq);
aq.fetch();
//lockFetchQueueTime += localLockFetchQueueTime = t.secs(utils::Timer::resetCounter);
} catch (cta::exception::Exception & ex) {
// The queue is now absent. We can remove its reference in the root entry.
// A new queue could have been added in the mean time, and be non-empty.
// We will then fail to remove from the RootEntry (non-fatal).
ScopedExclusiveLock rexl(re);
re.fetch();
try {
re.removeArchiveQueueAndCommit(cId, QueueType::LiveJobs, lc);
log::ScopedParamContainer params(lc);
params.add("tapepool", cId)
.add("queueObject", aq.getAddressIfSet());
lc.log(log::INFO, "In ArchiveMount::getNextJobBatch(): de-referenced missing queue from root entry");
} catch (RootEntry::ArchiveQueueNotEmpty & ex) {
// TODO: improve: if we fail here we could retry to fetch a job.
log::ScopedParamContainer params(lc);
params.add("tapepool", cId)
.add("queueObject", aq.getAddressIfSet())
.add("Message", ex.getMessageValue());
lc.log(log::INFO, "In ArchiveMount::getNextJobBatch(): could not de-referenced missing queue from root entry");
} catch (RootEntry::NoSuchArchiveQueue & ex) {
// Somebody removed the queue in the mean time. Barely worth mentioning.
log::ScopedParamContainer params(lc);
params.add("tapepool", cId)
.add("queueObject", aq.getAddressIfSet());
lc.log(log::DEBUG, "In ArchiveMount::getNextJobBatch(): could not de-referenced missing queue from root entry: already done.");
}
//emptyQueueCleanupTime += localEmptyCleanupQueueTime = t.secs(utils::Timer::resetCounter);
attemptCount++;
goto retry;
}
}
auto ContainerTraits<ArchiveQueue>::getPoppingElementsCandidates(Container& cont, PopCriteria& unfulfilledCriteria,
ElementsToSkipSet& elemtsToSkip, log::LogContext& lc) -> PoppedElementsBatch {
PoppedElementsBatch ret;
auto candidateJobsFromQueue=cont.getCandidateList(unfulfilledCriteria.bytes, unfulfilledCriteria.files, elemtsToSkip);
for (auto &cjfq: candidateJobsFromQueue.candidates) {
ret.elements.emplace_back(PoppedElement{cta::make_unique<ArchiveRequest>(cjfq.address, cont.m_objectStore), cjfq.copyNb, cjfq.size});
}
return ret;
}
auto ContainerTraits<ArchiveQueue>::getElementSummary(const PoppedElement& poppedElement) -> PoppedElementsSummary {
PoppedElementsSummary ret;
ret.bytes = poppedElement.bytes;
ret.files = 1;
return ret;
}
void ContainerTraits<ArchiveQueue>::PoppedElementsList::insertBack(PoppedElementsList&& insertedList) {
for (auto &e: insertedList) {
std::list<PoppedElement>::emplace_back(std::move(e));
}
}
void ContainerTraits<ArchiveQueue>::PoppedElementsList::insertBack(PoppedElement&& e) {
std::list<PoppedElement>::emplace_back(std::move(e));
}
auto ContainerTraits<ArchiveQueue>::PopCriteria::operator-=(const PoppedElementsSummary& pes) -> PopCriteria & {
bytes -= pes.bytes;
files -= pes.files;
return *this;
}
}} // namespace cta::objectstore
......@@ -29,112 +29,120 @@ public:
typedef std::string ContainerAddress;
typedef std::string ElementAddress;
typedef std::string ContainerIdentifyer;
struct Element {
struct InsertedElement {
std::unique_ptr<ArchiveRequest> archiveRequest;
uint16_t copyNb;
cta::common::dataStructures::ArchiveFile archiveFile;
cta::common::dataStructures::MountPolicy mountPolicy;
typedef std::list<InsertedElement> list;
};
typedef std::list<Element> ElementMemoryContainer;
struct ElementOpFailure {
template <class Element>
struct OpFailure {
Element * element;
std::exception_ptr failure;
typedef std::list<OpFailure> list;
};
typedef std::list<ElementOpFailure> ElementOpFailureContainer;
typedef ArchiveRequest::JobDump ElementDescriptor;
typedef std::list<ElementDescriptor> ElementDescriptorContainer;
template <class Element>
static ElementAddress getElementAddress(const Element & e) { return e.archiveRequest->getAddressIfSet(); }
static void getLockedAndFetched(Container & cont, ScopedExclusiveLock & aqL, AgentReference & agRef, const ContainerIdentifyer & contId,
log::LogContext & lc) {
Helpers::getLockedAndFetchedQueue<Container>(cont, aqL, agRef, contId, QueueType::LiveJobs, lc);
}
log::LogContext & lc);
static void addReferencesAndCommit(Container & cont, ElementMemoryContainer & elemMemCont,
AgentReference & agentRef, log::LogContext & lc) {
std::list<ArchiveQueue::JobToAdd> jobsToAdd;
for (auto & e: elemMemCont) {
ElementDescriptor jd;
jd.copyNb = e.copyNb;
jd.tapePool = cont.getTapePool();
jd.owner = cont.getAddressIfSet();
ArchiveRequest & ar = *e.archiveRequest;
jobsToAdd.push_back({jd, ar.getAddressIfSet(), e.archiveFile.archiveFileID, e.archiveFile.fileSize,
e.mountPolicy, time(nullptr)});
}
cont.addJobsAndCommit(jobsToAdd, agentRef, lc);
}
static void getLockedAndFetchedNoCreate(Container & cont, ScopedExclusiveLock & contLock, const ContainerIdentifyer & cId,
log::LogContext & lc);
static void removeReferencesAndCommit(Container & cont, ElementOpFailureContainer & elementsOpFailures) {
std::list<std::string> elementsToRemove;
for (auto & eof: elementsOpFailures) {
elementsToRemove.emplace_back(eof.element->archiveRequest->getAddressIfSet());
}
cont.removeJobsAndCommit(elementsToRemove);
}
static void addReferencesAndCommit(Container & cont, InsertedElement::list & elemMemCont,
AgentReference & agentRef, log::LogContext & lc);
void removeReferencesAndCommit(Container & cont, std::list<ElementAddress>& elementAddressList) {
cont.removeJobsAndCommit(elementAddressList);
}
static void removeReferencesAndCommit(Container & cont, OpFailure<InsertedElement>::list & elementsOpFailures);
static ElementOpFailureContainer switchElementsOwnership(ElementMemoryContainer & elemMemCont, const ContainerAddress & contAddress,
const ContainerAddress & previousOwnerAddress, log::LogContext & lc) {
std::list<std::unique_ptr<ArchiveRequest::AsyncJobOwnerUpdater>> updaters;
for (auto & e: elemMemCont) {
ArchiveRequest & ar = *e.archiveRequest;
auto copyNb = e.copyNb;
updaters.emplace_back(ar.asyncUpdateJobOwner(copyNb, contAddress, previousOwnerAddress));
}
auto u = updaters.begin();
auto e = elemMemCont.begin();
ElementOpFailureContainer ret;
while (e != elemMemCont.end()) {
try {
u->get()->wait();
} catch (...) {
ret.push_back(ElementOpFailure());
ret.back().element = &(*e);
ret.back().failure = std::current_exception();
}
u++;
e++;
}
return ret;
}
static void removeReferencesAndCommit(Container & cont, std::list<ElementAddress>& elementAddressList);
static OpFailure<InsertedElement>::list switchElementsOwnership(InsertedElement::list & elemMemCont,
const ContainerAddress & contAddress, const ContainerAddress & previousOwnerAddress, log::LogContext & lc);
class OwnershipSwitchFailure: public cta::exception::Exception {
public:
OwnershipSwitchFailure(const std::string & message): cta::exception::Exception(message) {};
ElementOpFailureContainer failedElements;
OpFailure<InsertedElement>::list failedElements;
};
class PoppedElement {
public:
std::unique_ptr<ArchiveRequest> archiveRequest;
uint16_t copyNb;
uint64_t bytes;
};
class PoppedElementsSummary;
class PopCriteria {
public:
PopCriteria();
PopCriteria& operator-= (const PoppedElementsSummary &);
uint64_t bytes;
uint64_t files;
};
class PoppedElementsList {
class PoppedElementsList: public std::list<PoppedElement> {
public:
PoppedElementsList();
void insertBack(PoppedElementsList &&);
void insertBack(PoppedElement &&);
};
class PoppedElementsSummary {
public:
PoppedElementsSummary();
bool operator< (const PopCriteria &);
PoppedElementsSummary& operator+= (const PoppedElementsSummary &);
uint64_t bytes;
uint64_t files;
bool operator< (const PopCriteria & pc) {
return bytes < pc.bytes && files < pc.files;
}
PoppedElementsSummary& operator+= (const PoppedElementsSummary & other) {
bytes += other.bytes;
files += other.files;
return *this;
}
};
class PoppedElementsBatch {
public:
PoppedElementsBatch();
PoppedElementsList elements;
PoppedElementsSummary summary;
};
typedef std::set<ElementAddress> ElementsToSkipSet;
static PoppedElementsSummary getElementSummary(const PoppedElement &);
static PoppedElementsBatch getPoppingElementsCandidates(Container & cont, PopCriteria & unfulfilledCriteria,
ElementsToSkipSet & elemtsToSkip, log::LogContext & lc);
CTA_GENERATE_EXCEPTION_CLASS(NoSuchContainer);
static OpFailure<PoppedElement>::list switchElementsOwnership(PoppedElementsBatch & popedElementBatch, const ContainerAddress & contAddress,
const ContainerAddress & previousOwnerAddress, log::LogContext & lc) {
std::list<std::unique_ptr<ArchiveRequest::AsyncJobOwnerUpdater>> updaters;
for (auto & e: popedElementBatch.elements) {
ArchiveRequest & ar = *e.archiveRequest;
auto copyNb = e.copyNb;
updaters.emplace_back(ar.asyncUpdateJobOwner(copyNb, contAddress, previousOwnerAddress));
}
auto u = updaters.begin();
auto e = popedElementBatch.elements.begin();
OpFailure<PoppedElement>::list ret;
while (e != popedElementBatch.elements.end()) {
try {
u->get()->wait();
} catch (...) {
ret.push_back(OpFailure<PoppedElement>());
ret.back().element = &(*e);
ret.back().failure = std::current_exception();
}
u++;
e++;
}
return ret;
}
};
}} // namespace cta::objectstore
\ No newline at end of file
......@@ -60,6 +60,7 @@ add_library (ctaobjectstore SHARED
AgentWatchdog.cpp
ArchiveQueue.cpp
ArchiveQueueShard.cpp
ArchiveQueueAlgorithms.cpp