Commit 4f040a9b authored by Steven Murray's avatar Steven Murray
Browse files

A cleaner is now always ran when you type /etc/init.d/tapeserverd stop

parent 7bea3a41
......@@ -29,4 +29,7 @@ message ForkCleaner {
// Description of the tape associated with the drive
required string vid = 5;
// Description of the cleaner job
required uint32 drivereadydelayinseconds = 6;
}
......@@ -35,9 +35,11 @@ castor::tape::tapeserver::daemon::CatalogueCleanerSession *
const tape::utils::DriveConfig &driveConfig,
ProcessForkerProxy &processForker,
const std::string &vid,
const time_t assignmentTime) {
const time_t assignmentTime,
const uint32_t driveReadyDelayInSeconds) {
const pid_t pid = processForker.forkCleaner(driveConfig, vid);
const pid_t pid = processForker.forkCleaner(driveConfig, vid,
driveReadyDelayInSeconds);
return new CatalogueCleanerSession(
log,
......
......@@ -54,6 +54,8 @@ public:
* be set to the empty string.
* @param assignmentTime The time at which a job was assigned to the tape
* drive.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
* @return A newly created CatalogueCleanerSession object.
*/
static CatalogueCleanerSession *create(
......@@ -62,7 +64,8 @@ public:
const tape::utils::DriveConfig &driveConfig,
ProcessForkerProxy &processForker,
const std::string &vid,
const time_t assignmentTime);
const time_t assignmentTime,
const uint32_t driveReadyDelayInSeconds);
/**
* Handles a tick in time. Time driven actions such as alarms should be
......
......@@ -524,7 +524,8 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::receivedLabelJob(
// createCleaner
//-----------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::createCleaner(
const std::string &vid, const time_t assignmentTime) {
const std::string &vid, const time_t assignmentTime,
const uint32_t driveReadyDelayInSeconds) {
try {
// Create a cleaner session
m_session = CatalogueCleanerSession::create(
......@@ -533,7 +534,8 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::createCleaner(
m_config,
m_processForker,
vid,
assignmentTime);
assignmentTime,
driveReadyDelayInSeconds);
} catch(castor::exception::Exception &ne) {
castor::exception::Exception ex;
ex.getMessage() << "Failed to create cleaner session: " <<
......@@ -591,7 +593,9 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::sessionFailed() {
session->sessionFailed();
if(CatalogueSession::SESSION_TYPE_CLEANER != session->getType()) {
createCleaner(session->getVid(), session->getAssignmentTime());
const uint32_t driveReadyDelayInSeconds = 60;
createCleaner(session->getVid(), session->getAssignmentTime(),
driveReadyDelayInSeconds);
} else {
changeState(DRIVE_STATE_DOWN);
m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
......@@ -605,7 +609,9 @@ void castor::tape::tapeserver::daemon::CatalogueDrive::sessionFailed() {
session->sessionFailed();
changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);
createCleaner(session->getVid(), session->getAssignmentTime());
const uint32_t driveReadyDelayInSeconds = 60;
createCleaner(session->getVid(), session->getAssignmentTime(),
driveReadyDelayInSeconds);
}
break;
case DRIVE_STATE_WAITSHUTDOWNCLEANER:
......@@ -803,44 +809,58 @@ time_t castor::tape::tapeserver::daemon::CatalogueDrive::
// shutdown
//------------------------------------------------------------------------------
void castor::tape::tapeserver::daemon::CatalogueDrive::shutdown() {
const DriveState previousState = m_state;
// If there is no running session
if(NULL == m_session) {
changeState(DRIVE_STATE_SHUTDOWN);
if(DRIVE_STATE_DOWN != previousState) {
m_vdqm.setDriveDown(m_hostName, m_config.unitName, m_config.dgn);
}
changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);
return;
}
// Create a cleaner process to make 100% sure the tape drive is empty
const std::string vid = ""; // Empty string means VID is not known
const time_t assignmentTime = time(NULL);
const uint32_t driveReadyDelayInSeconds = 0;
createCleaner(vid, assignmentTime, driveReadyDelayInSeconds);
changeState(DRIVE_STATE_WAITSHUTDOWNKILL);
// Else there is a running session
} else {
const pid_t sessionPid = m_session->getPid();
const CatalogueSession::Type sessionType = m_session->getType();
const char *sessionTypeStr =
CatalogueSession::sessionTypeToStr(sessionType);
// If the running session is a cleaner
if(CatalogueSession::SESSION_TYPE_CLEANER == m_session->getType()) {
std::list<log::Param> params;
params.push_back(log::Param("unitName", m_config.unitName));
params.push_back(log::Param("sessionType", sessionTypeStr));
params.push_back(log::Param("sessionPid", sessionPid));
changeState(DRIVE_STATE_WAITSHUTDOWNCLEANER);
// Kill the non-cleaner session
if(kill(sessionPid, SIGKILL)) {
const std::string message = castor::utils::errnoToString(errno);
params.push_back(log::Param("message", message));
m_log(LOG_ERR, "Failed to kill non-cleaner session whilst shutting down",
params);
// Else the running session is not a cleaner
} else {
// Nothing else can be done, mark drive as shutdown and return
changeState(DRIVE_STATE_SHUTDOWN);
changeState(DRIVE_STATE_WAITSHUTDOWNKILL);
return;
}
m_log(LOG_WARNING, "Sent SIGKILL to tape-session child-process", params);
const pid_t sessionPid = m_session->getPid();
const CatalogueSession::Type sessionType = m_session->getType();
const char *sessionTypeStr =
CatalogueSession::sessionTypeToStr(sessionType);
std::list<log::Param> params;
params.push_back(log::Param("unitName", m_config.unitName));
params.push_back(log::Param("sessionType", sessionTypeStr));
params.push_back(log::Param("sessionPid", sessionPid));
// Kill the non-cleaner session
if(kill(sessionPid, SIGKILL)) {
const std::string message = castor::utils::errnoToString(errno);
params.push_back(log::Param("message", message));
m_log(LOG_ERR, "Failed to kill non-cleaner session whilst shutting"
" down", params);
// Nothing else can be done, mark drive as shutdown
changeState(DRIVE_STATE_SHUTDOWN);
} else {
m_log(LOG_WARNING, "Sent SIGKILL to tape-session child-process",
params);
}
} // Else the running session is not a cleaner
} // Else there is a running session
}
//------------------------------------------------------------------------------
......
......@@ -333,8 +333,11 @@ public:
* @param The assignment time associated with the tape drive or 0 if not
* known. The assignment time is given as the number of seconds elapsed
* since the Epoch.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
*/
void createCleaner(const std::string &vid, const time_t assignmentTime);
void createCleaner(const std::string &vid, const time_t assignmentTime,
const uint32_t driveReadyDelayInSeconds);
/**
* Moves the state of the tape drive to DRIVE_STATE_UP if the
......
......@@ -32,13 +32,15 @@ castor::tape::tapeserver::daemon::CleanerSession::CleanerSession(
castor::log::Logger &log,
const utils::DriveConfig &driveConfig,
System::virtualWrapper &sysWrapper,
const std::string &vid):
const std::string &vid,
const uint32_t driveReadyDelayInSeconds):
m_capUtils(capUtils),
m_mc(mc),
m_log(log),
m_driveConfig(driveConfig),
m_sysWrapper(sysWrapper),
m_vid(vid) {
m_vid(vid),
m_driveReadyDelayInSeconds(driveReadyDelayInSeconds) {
}
//------------------------------------------------------------------------------
......@@ -69,11 +71,15 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
}
//temporization to allow for actions to complete
try {
drive->waitUntilReady(60); //wait 1 minute for a possible ongoing mount to complete or for an IO operation to complete
} catch (castor::exception::Exception &ex) {
log::Param params[] = {log::Param("message", ex.getMessage().str())};
m_log(LOG_INFO, "Cleaner session caught a non-fatal exception while waiting for the drive to become ready. One of the reasons we get here is if the drive has no tape inside.", params);
if(0 != m_driveReadyDelayInSeconds) {
try {
drive->waitUntilReady(m_driveReadyDelayInSeconds);
} catch (castor::exception::Exception &ex) {
log::Param params[] = {log::Param("message", ex.getMessage().str())};
m_log(LOG_INFO, "Cleaner session caught a non-fatal exception whilst"
" waiting for the drive to become ready. One of the reasons we get here"
" is if the drive has no tape inside.", params);
}
}
//here we check if the drive contains a tape: if not, there's nothing to clean
......
......@@ -55,6 +55,8 @@ namespace daemon {
* @param sysWrapper Object representing the operating system.
* @param vid The volume identifier of the mounted tape if known,
* else the empty string.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
*/
CleanerSession(
server::ProcessCap &capUtils,
......@@ -62,7 +64,8 @@ namespace daemon {
castor::log::Logger &log,
const utils::DriveConfig &driveConfig,
System::virtualWrapper &sysWrapper,
const std::string &vid);
const std::string &vid,
const uint32_t driveReadyDelayInSeconds);
/**
* Execute the session and return the type of action to be performed
......@@ -118,6 +121,12 @@ namespace daemon {
* string.
*/
const std::string m_vid;
/**
* The maximum number of seconds to wait for the drive to be raedy with a
* tape inside of it.
*/
const uint32_t m_driveReadyDelayInSeconds;
}; // class CleanerSession
......
......@@ -289,6 +289,8 @@ castor::tape::tapeserver::daemon::ProcessForker::MsgHandlerResult
std::list<log::Param> params;
params.push_back(log::Param("unitName", rqst.unitname()));
params.push_back(log::Param("vid", rqst.vid()));
params.push_back(log::Param("driveReadyDelayInSeconds",
rqst.drivereadydelayinseconds()));
m_log(LOG_INFO, "ProcessForker handling ForkCleaner message", params);
// Fork a label session
......@@ -492,7 +494,8 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
m_log,
driveConfig,
sWrapper,
rqst.vid());
rqst.vid(),
rqst.drivereadydelayinseconds());
return cleanerSession.execute();
} catch(castor::exception::Exception &ex) {
throw ex;
......
......@@ -241,7 +241,9 @@ void castor::tape::tapeserver::daemon::ProcessForkerConnectionHandler::
const std::string vid = drive.getVidForCleaner();
const time_t assignmentTime = drive.getAssignmentTimeForCleaner();
drive.sessionFailed();
return drive.createCleaner(vid, assignmentTime);
const uint32_t driveReadyDelayInSeconds = 60;
return drive.createCleaner(vid, assignmentTime,
driveReadyDelayInSeconds);
}
default:
// Should never happen
......
......@@ -81,10 +81,12 @@ public:
* tape in the drive if there is in fact a tape in the drive and its volume
* identifier is known. If the volume identifier is not known then this
* parameter should be set to an empty string.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
* @return The process identifier of the newly forked session.
*/
virtual pid_t forkCleaner(const utils::DriveConfig &driveConfig,
const std::string &vid) = 0;
const std::string &vid, const uint32_t driveReadyDelayInSeconds) = 0;
}; // class ProcessForkerProxy
......
......@@ -55,7 +55,8 @@ pid_t castor::tape::tapeserver::daemon::ProcessForkerProxyDummy::
// forkCleaner
//------------------------------------------------------------------------------
pid_t castor::tape::tapeserver::daemon::ProcessForkerProxyDummy::
forkCleaner(const utils::DriveConfig &driveConfig, const std::string &vid) {
forkCleaner(const utils::DriveConfig &driveConfig, const std::string &vid,
const uint32_t driveReadyDelayInSeconds) {
// This is a dummy method and so intentionally does nothing
return 0;
}
......@@ -82,19 +82,17 @@ public:
/**
* Forks a cleaner session for the specified tape drive.
*
* PLEASE NOTE that this method is a dummy method and intentionally does
* nothing.
*
* @param driveConfig The configuration of the tape drive.
* @param vid If known then this string specifies the volume identifier of the
* tape in the drive if there is in fact a tape in the drive and its volume
* identifier is known. If the volume identifier is not known then this
* parameter should be set to an empty string.
* @return The process identifier of the newly forked session which will
* always be 0 because this is a dummy method.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
* @return The process identifier of the newly forked session.
*/
pid_t forkCleaner(const utils::DriveConfig &driveConfig,
const std::string &vid);
const std::string &vid, const uint32_t driveReadyDelayInSeconds);
}; // class ProcessForkerProxySocket
......
......@@ -183,10 +183,12 @@ castor::messages::ForkLabel castor::tape::tapeserver::daemon::
// forkCleaner
//------------------------------------------------------------------------------
pid_t castor::tape::tapeserver::daemon::ProcessForkerProxySocket::
forkCleaner(const utils::DriveConfig &driveConfig, const std::string &vid) {
forkCleaner(const utils::DriveConfig &driveConfig, const std::string &vid,
const uint32_t driveReadyDelayInSeconds) {
// Request the process forker to fork a label session
const messages::ForkCleaner rqst = createForkCleanerMsg(driveConfig, vid);
const messages::ForkCleaner rqst = createForkCleanerMsg(driveConfig, vid,
driveReadyDelayInSeconds);
ProcessForkerUtils::writeFrame(m_socketFd, rqst);
// Read back the reply
......@@ -205,7 +207,8 @@ pid_t castor::tape::tapeserver::daemon::ProcessForkerProxySocket::
//------------------------------------------------------------------------------
castor::messages::ForkCleaner castor::tape::tapeserver::daemon::
ProcessForkerProxySocket::createForkCleanerMsg(
const utils::DriveConfig &driveConfig, const std::string &vid) {
const utils::DriveConfig &driveConfig, const std::string &vid,
const uint32_t driveReadyDelayInSeconds) {
messages::ForkCleaner msg;
// Description of the tape drive
......@@ -214,5 +217,8 @@ castor::messages::ForkCleaner castor::tape::tapeserver::daemon::
// Description of the tape
msg.set_vid(vid);
// Description of the cleaner job
msg.set_drivereadydelayinseconds(driveReadyDelayInSeconds);
return msg;
}
......@@ -96,16 +96,18 @@ public:
/**
* Forks a cleaner session for the specified tape drive.
*
*
* @param driveConfig The configuration of the tape drive.
* @param vid If known then this string specifies the volume identifier of the
* tape in the drive if there is in fact a tape in the drive and its volume
* identifier is known. If the volume identifier is not known then this
* parameter should be set to an empty string.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
* @return The process identifier of the newly forked session.
*/
pid_t forkCleaner(const utils::DriveConfig &driveConfig,
const std::string &vid);
const std::string &vid, const uint32_t driveReadyDelayInSeconds);
private:
......@@ -193,10 +195,13 @@ private:
* @param driveConfig The configuration of the tape drive.
* @param vid The volume identifier of the tape associated with the tape
* drive.
* @param driveReadyDelayInSeconds The maximum number of seconds to wait for
* the drive to be raedy with a tape inside of it.
* @return The message.
*/
messages::ForkCleaner createForkCleanerMsg(
const utils::DriveConfig &driveConfig, const std::string &vid);
const utils::DriveConfig &driveConfig, const std::string &vid,
const uint32_t driveReadyDelayInSeconds);
}; // class ProcessForkerProxySocket
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment