Commit 14a4ee90 authored by Steven Murray's avatar Steven Murray
Browse files

bug #85949: RFE: Add bulk messages to tapegatewayd/tapebridged protocol

Merged v2_1_11Version-TapeBulkProtocols branch into trunk.
parent 855e3eda
......@@ -29,6 +29,7 @@
#include "castor/tape/tapebridge/BridgeSocketCatalogue.hpp"
#include "castor/tape/tapebridge/Constants.hpp"
#include "castor/tape/tapebridge/Counter.hpp"
#include "castor/tape/tapebridge/FileWrittenNotificationList.hpp"
#include "castor/tape/tapebridge/PendingMigrationsStore.hpp"
#include "castor/tape/tapebridge/TapeFlushConfigParams.hpp"
#include "castor/tape/legacymsg/CommonMarshal.hpp"
......@@ -114,15 +115,13 @@ private:
* The catalogue of all the rtcpd and tapegateway connections used by the
* bridge protocol engine.
*
* The catalogue behaves like a smart pointer for the rtcpd disk/tape IO
* control-connections and the client connections in that its destructor will
* close them if they are still open.
* The catalogue behaves as a smart pointer for the initial rtcpd connection,
* the rtcpd disk/tape IO control-connections and the client connections. In
* other words the destructor of the catalogue will close these connections
* if they are still open.
*
* The catalogue will not close the listen socket used to accept rtcpd
* connections. This is the responsibility of the VdqmRequestHandler.
*
* The catalogue will not close the initial rtcpd connection. This is the
* responsibility of the VdqmRequestHandler.
*/
BridgeSocketCatalogue m_sockCatalogue;
......@@ -140,7 +139,7 @@ private:
* If migrating and the client is the tape-gateway, then this is the next
* expected tape file sequence, else this member is ignored.
*/
uint32_t m_nextDestinationFseq;
int32_t m_nextDestinationTapeFSeq;
/**
* Functor that returns true if the daemon is stopping gracefully.
......@@ -195,6 +194,19 @@ private:
*/
PendingMigrationsStore m_pendingMigrationsStore;
/**
* A list of lists, where each sub-list represents a batch of files that were
* flushed to tape by a common flush.
*/
std::list<FileWrittenNotificationList> m_flushedBatches;
/**
* This member variable is set to true when the session with the rtcpd
* daemon has been finished and therefore all connections with the rtcpd
* daemon, accept for the initial callback connection are closed.
*/
bool m_sessionWithRtcpdIsFinished;
/**
* In-line helper function that returns a 64-bit rtcpd message body handler
* key to be used in the m_rtcpdHandler map.
......@@ -252,7 +264,7 @@ private:
*/
typedef void (BridgeProtocolEngine::*ClientMsgCallback)(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -289,9 +301,8 @@ private:
* released from the catalogue and newly accepted connections added.
*
* @param readFdSet The read file-descriptor set from calling select().
* @return True if the RTCOPY session should continue else false.
*/
bool processAPendingSocket(fd_set &readFdSet)
void processAPendingSocket(fd_set &readFdSet)
throw (castor::exception::Exception);
/**
......@@ -301,7 +312,7 @@ private:
* Please note that this method will modify the catalogue of
* socket-descriptors as necessary.
*/
bool processPendingListenSocket() throw (castor::exception::Exception);
void processPendingListenSocket() throw (castor::exception::Exception);
/**
* Processes the specified socket which must be both pending and the initial
......@@ -309,7 +320,7 @@ private:
*
* @param pendingSock the file descriptior of the pending socket.
*/
bool processPendingInitialRtcpdSocket(const int pendingSock)
void processPendingInitialRtcpdSocket(const int pendingSock)
throw (castor::exception::Exception);
/**
......@@ -321,20 +332,33 @@ private:
*
* @param pendingSock the file descriptior of the pending socket.
*/
bool processPendingRtcpdDiskTapeIOControlSocket(const int pendingSock)
void processPendingRtcpdDiskTapeIOControlSocket(const int pendingSock)
throw (castor::exception::Exception);
/**
* Processes the specified socket which must be both pending and a connection
* made from this tapebridged daemon to a client (readtp, writetp, dumtp or
* a tapebridged daemon).
* made from this tapebridged daemon to a client (readtp, writetp, dumptp or
* tapegatewayd).
*
* Please note that this method will modify the catalogue of
* socket-descriptors as necessary.
*
* @param pendingSock the file descriptior of the pending socket.
*/
bool processPendingClientSocket(const int pendingSock)
void processPendingClientSocket(const int pendingSock)
throw (castor::exception::Exception);
/**
* Processes the specified socket which must be both pending and a connection
* made from this tapebridged daemon to a migration client (writetp or
* tapegatewayd).
*
* Please note that this method will modify the catalogue of
* socket-descriptors as necessary.
*
* @param pendingSock the file descriptior of the pending socket.
*/
void processPendingClientMigrationReportSocket(const int pendingSock)
throw (castor::exception::Exception);
/**
......@@ -511,14 +535,12 @@ private:
throw(castor::exception::Exception);
/**
* Sends the specified file-migrated notification to the client (the
* tapegatewayd daemon or the writetp command-line tool).
*
* This method sets the aggregatorTransactionId of each notification message
* ccordingly before sending the message.
* Sends the "file flushed to tape" notifications that correspond to the
* specified "file written to tape" notifications that have now received
* their corresponding "flushed to tape" message from the rtcpd daemon.
*/
void sendFlushedMigrationsToClient(
std::list<tapegateway::FileMigratedNotification> &fileMigratedNotifications)
const FileWrittenNotificationList &notifications)
throw (castor::exception::Exception);
/**
......@@ -556,14 +578,14 @@ private:
throw(castor::exception::Exception);
/**
* FileToMigrate client message handler.
* FilesToMigrateList client message handler.
*
* For full documenation please see the documentation of the type
* BridgeProtocolEngine::ClientMsgCallback.
*/
void fileToMigrateClientCallback(
void filesToMigrateListClientCallback(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -573,14 +595,14 @@ private:
throw(castor::exception::Exception);
/**
* FileToRecall client message handler.
* FilesToRecallListClientCallback client message handler.
*
* For full documenation please see the documentation of the type
* BridgeProtocolEngine::ClientMsgCallback.
*/
void fileToRecallClientCallback(
void filesToRecallListClientCallback(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -597,7 +619,7 @@ private:
*/
void noMoreFilesClientCallback(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -614,7 +636,7 @@ private:
*/
void endNotificationErrorReportClientCallback(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -631,7 +653,7 @@ private:
*/
void notificationAcknowledge(
const int clientSock,
const IObject *const obj,
IObject *const obj,
const int rtcpdSock,
const uint32_t rtcpdMagic,
const uint32_t rtcpdReqType,
......@@ -640,6 +662,18 @@ private:
const struct timeval clientReqTimeStamp)
throw(castor::exception::Exception);
/**
* Notifies the client of the end of session.
*/
void notifyClientEndOfSession();
/**
* Notifies the rtcpd daemon of the end of session using the initial
* rtcpd connection and the closes the initial rtcpd connection.
*/
void notifyRtcpdEndOfSessionAndCloseInitialConnection()
throw(castor::exception::Exception);
}; // class BridgeProtocolEngine
} // namespace tapebridge
......
......@@ -48,6 +48,9 @@ castor::tape::tapebridge::BridgeSocketCatalogue::~BridgeSocketCatalogue() {
// Note this destructor does NOT close the initial rtcpd connection. This is
// the responsibility of the VdqmRequestHandler.
if(0 <= m_initialRtcpdSock) {
close(m_initialRtcpdSock);
}
// For each rtcpd-connection
for(RtcpdConnectionList::const_iterator itor = m_rtcpdConnections.begin();
......@@ -57,10 +60,15 @@ castor::tape::tapebridge::BridgeSocketCatalogue::~BridgeSocketCatalogue() {
close(itor->rtcpdSock);
// If there is an associated client connection, then close it
if(itor->clientSock != -1) {
if(0 <= itor->clientSock) {
close(itor->clientSock);
}
}
// If there is an open client migration-report connection, then close it
if(0 <= m_clientMigrationReportConnection.clientSock) {
close(m_clientMigrationReportConnection.clientSock);
}
}
......@@ -70,14 +78,14 @@ castor::tape::tapebridge::BridgeSocketCatalogue::~BridgeSocketCatalogue() {
void castor::tape::tapebridge::BridgeSocketCatalogue::addListenSock(
const int listenSock) throw(castor::exception::Exception) {
if(listenSock < 0) {
if(0 > listenSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid socket-descriptor"
": Value is negative"
": listenSock=" << listenSock);
}
if(m_listenSock != -1) {
if(0 <= m_listenSock) {
TAPE_THROW_CODE(ECANCELED,
": Listen socket-descriptor is already set"
": current listenSock=" << m_listenSock <<
......@@ -94,14 +102,14 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::addListenSock(
void castor::tape::tapebridge::BridgeSocketCatalogue::addInitialRtcpdConn(
const int initialRtcpdSock) throw(castor::exception::Exception) {
if(initialRtcpdSock < 0) {
if(0 > initialRtcpdSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid socket-descriptor"
": Value is negative"
": initialRtcpdSock=" << initialRtcpdSock);
}
if(m_initialRtcpdSock != -1) {
if(0 <= m_initialRtcpdSock) {
TAPE_THROW_CODE(ECANCELED,
": Initial rtcpd socket-descriptor is already set"
": current initialRtcpdSocket=" << m_initialRtcpdSock <<
......@@ -112,6 +120,24 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::addInitialRtcpdConn(
}
//-----------------------------------------------------------------------------
// releaseInitialRtcpdConn
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::releaseInitialRtcpdConn()
throw(castor::exception::Exception) {
// Throw an exception if the socket-descriptor has not been set
if(0 > m_initialRtcpdSock) {
TAPE_THROW_CODE(ENOENT,
": Initial rtcpd socket-descriptor does not exist in the catalogue");
}
// Release and return the socket-descriptor
const int tmpSock = m_initialRtcpdSock;
m_initialRtcpdSock = -1;
return tmpSock;
}
//-----------------------------------------------------------------------------
// addRtcpdDiskTapeIOControlConn
//-----------------------------------------------------------------------------
......@@ -119,7 +145,7 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::
addRtcpdDiskTapeIOControlConn(const int rtcpdSock)
throw(castor::exception::Exception) {
if(rtcpdSock < 0) {
if(0 > rtcpdSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid socket-descriptor"
": Value is negative"
......@@ -155,14 +181,14 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::addClientConn(
const uint64_t aggregatorTransactionId)
throw(castor::exception::Exception) {
if(rtcpdSock < 0) {
if(0 > rtcpdSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid rtcpd socket-descriptor"
": Value is negative"
": rtcpdSock=" << rtcpdSock);
}
if(clientSock < 0) {
if(0 > clientSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid client socket-descriptor"
": Value is negative"
......@@ -177,7 +203,7 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::addClientConn(
if(itor->rtcpdSock == rtcpdSock) {
// Throw an exception if there is already an associated client connection
if(itor->clientSock != -1) {
if(0 <= itor->clientSock) {
TAPE_THROW_CODE(ECANCELED,
": There is already an associated client connection"
": current clientSock=" << itor->clientSock <<
......@@ -227,12 +253,12 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::addClientConn(
//-----------------------------------------------------------------------------
// getListenSock
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::getListenSock()
int castor::tape::tapebridge::BridgeSocketCatalogue::getListenSock() const
throw(castor::exception::Exception) {
// Throw an exception if the socket-descriptor of the listen socket does not
// exist in the catalogue
if(m_listenSock == -1) {
if(0 > m_listenSock) {
TAPE_THROW_CODE(ENOENT,
": Listen socket-descriptor does not exist in the catalogue");
}
......@@ -245,11 +271,11 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::getListenSock()
// getInitialRtcpdConn
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::getInitialRtcpdConn()
throw(castor::exception::Exception) {
const throw(castor::exception::Exception) {
// Throw an exception if the socket-descriptor of the initial rtcpd
// connection does not exist in the catalogue
if(m_initialRtcpdSock == -1) {
if(0 > m_initialRtcpdSock) {
TAPE_THROW_CODE(ENOENT,
": Initial rtcpd socket-descriptor does not exist in the catalogue");
}
......@@ -265,7 +291,7 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::
releaseRtcpdDiskTapeIOControlConn(const int rtcpdSock)
throw(castor::exception::Exception) {
if(rtcpdSock < 0) {
if(0 > rtcpdSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid socket-descriptor"
": Value is negative"
......@@ -308,14 +334,14 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::releaseClientConn(
const int rtcpdSock, const int clientSock)
throw(castor::exception::Exception) {
if(rtcpdSock < 0) {
if(0 > rtcpdSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid rtcpd socket-descriptor"
": Value is negative"
": rtcpdSock=" << rtcpdSock);
}
if(clientSock < 0) {
if(0 > clientSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid client socket-descriptor"
": Value is negative"
......@@ -383,12 +409,12 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::getRtcpdConn(
int &rtcpdSock,
uint32_t &rtcpdReqMagic,
uint32_t &rtcpdReqType,
char *&rtcpdReqTapePath,
const char *&rtcpdReqTapePath,
uint64_t &aggregatorTransactionId,
struct timeval &clientReqTimeStamp)
struct timeval &clientReqTimeStamp) const
throw(castor::exception::Exception) {
if(clientSock < 0) {
if(0 > clientSock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid client socket-descriptor"
": Value is negative"
......@@ -396,7 +422,7 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::getRtcpdConn(
}
// For each rtcpd-connection
for(RtcpdConnectionList::iterator itor = m_rtcpdConnections.begin();
for(RtcpdConnectionList::const_iterator itor = m_rtcpdConnections.begin();
itor != m_rtcpdConnections.end(); itor++) {
// If the association has been found, then set the output parameters and
......@@ -427,29 +453,38 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::getRtcpdConn(
// buildReadFdSet
//-----------------------------------------------------------------------------
void castor::tape::tapebridge::BridgeSocketCatalogue::buildReadFdSet(
fd_set &readFdSet, int &maxFd) throw() {
fd_set &readFdSet, int &maxFd) const throw() {
// Clear the file-descriptor set
FD_ZERO(&readFdSet);
// If the listen socket has been set, then add it to the descriptor set and
// update maxFd accordingly
if(m_listenSock != -1) {
if(0 <= m_listenSock) {
FD_SET(m_listenSock, &readFdSet);
maxFd = m_listenSock;
}
// If the initial rtcpd connection socket has been set, then add it to the
// descriptor set and update maxFd accordingly
if(m_initialRtcpdSock != -1) {
if(0 <= m_initialRtcpdSock) {
FD_SET(m_initialRtcpdSock, &readFdSet);
if(m_initialRtcpdSock > maxFd) {
maxFd = m_initialRtcpdSock;
}
}
// If the client migration-report connection socket has been set, then add it
// to the descriptor set and update maxFd accordingly
if(0 <= m_clientMigrationReportConnection.clientSock) {
FD_SET(m_clientMigrationReportConnection.clientSock, &readFdSet);
if(m_clientMigrationReportConnection.clientSock > maxFd) {
maxFd = m_clientMigrationReportConnection.clientSock;
}
}
// For each rtcpd-connection
for(RtcpdConnectionList::iterator itor = m_rtcpdConnections.begin();
for(RtcpdConnectionList::const_iterator itor = m_rtcpdConnections.begin();
itor != m_rtcpdConnections.end(); itor++) {
// Add the rtcpd socket-descriptor to the descriptor set and update maxFd
......@@ -461,7 +496,7 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::buildReadFdSet(
// If there is an associated client socket-descriptor, then add it to
// the descriptor set and update maxFd accordingly
if(itor->clientSock != -1) {
if(0 <= itor->clientSock) {
FD_SET(itor->clientSock, &readFdSet);
if(itor->clientSock > maxFd) {
maxFd = itor->clientSock;
......@@ -475,24 +510,32 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::buildReadFdSet(
// getAPendingSock
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::getAPendingSock(
fd_set &readFdSet, SocketType &sockType) throw() {
fd_set &readFdSet, SocketType &sockType) const {
// If the listen socket is pending, then set the socket type output parameter
// and return the socket
if(FD_ISSET(m_listenSock, &readFdSet)) {
// If the listen socket is set and is pending, then set the socket type
// output parameter and return the socket
if(0 <= m_listenSock && FD_ISSET(m_listenSock, &readFdSet)) {
sockType = LISTEN;
return m_listenSock;
}
// If the initial rtcpd connection socket is pending, then set the socket
// type output parameter and return the socket
if(FD_ISSET(m_initialRtcpdSock, &readFdSet)) {
// If the initial rtcpd connection socket is set and pending, then set the
// socket type output parameter and return the socket
if(0 <= m_initialRtcpdSock && FD_ISSET(m_initialRtcpdSock, &readFdSet)) {
sockType = INITIAL_RTCPD;
return m_initialRtcpdSock;
}
// If the client migration-report connection is set and pending, then set the
// socket type output parameter and return the socket
if(0 <= m_clientMigrationReportConnection.clientSock &&
FD_ISSET(m_clientMigrationReportConnection.clientSock, &readFdSet)) {
sockType = CLIENT_MIGRATION_REPORT;
return m_clientMigrationReportConnection.clientSock;
}
// For each rtcpd-connection
for(RtcpdConnectionList::iterator itor = m_rtcpdConnections.begin();
for(RtcpdConnectionList::const_iterator itor = m_rtcpdConnections.begin();
itor != m_rtcpdConnections.end(); itor++) {
// If the rtcpd socket-descriptor is pending, then set the socket type
......@@ -503,7 +546,7 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::getAPendingSock(
}
// If there is an associated client socket-descriptor
if(itor->clientSock != -1) {
if(0 <= itor->clientSock) {
// If the rtcpd socket-descriptor is pending, then set the socket type
// output parameter and return the socket
if(FD_ISSET(itor->clientSock, &readFdSet)) {
......@@ -523,7 +566,7 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::getAPendingSock(
// getNbDiskTapeIOControlConnections
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::
getNbDiskTapeIOControlConns() {
getNbDiskTapeIOControlConns() const {
return m_rtcpdConnections.size();
}
......@@ -532,7 +575,7 @@ int castor::tape::tapebridge::BridgeSocketCatalogue::
//-----------------------------------------------------------------------------
// checkForTimeout
//-----------------------------------------------------------------------------
void castor::tape::tapebridge::BridgeSocketCatalogue::checkForTimeout()
void castor::tape::tapebridge::BridgeSocketCatalogue::checkForTimeout() const
throw(castor::exception::TimeOut) {
if(!m_clientReqHistory.empty()) {
......@@ -543,7 +586,7 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::checkForTimeout()
gettimeofday(&now, NULL);
// Get the oldest client request
ClientReqHistoryElement &clientRequest = m_clientReqHistory.front();
const ClientReqHistoryElement &clientRequest = m_clientReqHistory.front();
// Calculate the age in seconds
const int ageSecs = clientRequest.clientReqTimeStamp.tv_sec - now.tv_sec;
......@@ -563,3 +606,66 @@ void castor::tape::tapebridge::BridgeSocketCatalogue::checkForTimeout()
}
}
}
//-----------------------------------------------------------------------------
// addClientMigrationReportSock
//-----------------------------------------------------------------------------
void castor::tape::tapebridge::BridgeSocketCatalogue::
addClientMigrationReportSock(const int sock,
const uint64_t aggregatorTransactionId) throw(castor::exception::Exception) {
// Throw an exception if the socket-descriptor is invalid
if(0 > sock) {
TAPE_THROW_EX(castor::exception::InvalidArgument,
": Invalid socket-descriptor"
": Value is negative"
": sock=" << sock);
}
// Throw an exception if the client migraton-report socket-descriptor has
// already been set
if(0 <= m_clientMigrationReportConnection.clientSock) {
TAPE_THROW_CODE(EEXIST,
": client migration-report socket-descriptor is already set"
": current value=" << m_clientMigrationReportConnection.clientSock <<
": new value =" << sock);
}
m_clientMigrationReportConnection.clientSock = sock;
m_clientMigrationReportConnection.aggregatorTransactionId =
aggregatorTransactionId;
}
//-----------------------------------------------------------------------------
// clientMigrationReportSockIsSet
//-----------------------------------------------------------------------------
bool castor::tape::tapebridge::BridgeSocketCatalogue::
clientMigrationReportSockIsSet() const {
return 0 <= m_clientMigrationReportConnection.clientSock;
}
//-----------------------------------------------------------------------------
// releaseClientMigrationReportSock
//-----------------------------------------------------------------------------
int castor::tape::tapebridge::BridgeSocketCatalogue::
releaseClientMigrationReportSock(uint64_t &aggregatorTransactionId)
throw(castor::exception::Exception) {
// Throw an exception if the socket-descriptor has not been set
if(0 > m_clientMigrationReportConnection.clientSock) {
TAPE_THROW_CODE(ENOENT,
": Client migration-report socket-descriptor does not exist in the"
" catalogue");
}