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

CASTOR-4749: tapeserverd must NOT treat tapegateway::NoMoreFiles as an error...

CASTOR-4749: tapeserverd must NOT treat tapegateway::NoMoreFiles as an error in response to a tapegateway::VolumeRequest

A new unit test has been created for validating that Volume request -> No More Files is not considered as an error.

The code has been changed accordingly. EndNotificationErrorReport is still considered an error.
parent 5a714693
......@@ -149,7 +149,7 @@ void ClientProxy::fetchVolumeId(
// 3) c) End notification error report.
} else if (NULL != (errorReport = dynamic_cast<tapegateway::EndNotificationErrorReport *>(
response.get()))) {
EndOfSession eos("Client replied noMoreFiles directly to volume request: ");
EndOfSessionWithError eos("Client sent an end session with error to volume request: ");
eos.getMessage() << "errorCode=" << errorReport->errorCode()
<< "errorReport=\"" << errorReport->errorMessage() << "\"";
throw eos;
......
......@@ -143,6 +143,13 @@ namespace client {
EndOfSession(std::string w=""):castor::exception::Exception(w) {}
};
/**
* Exception marking end of with error
*/
class EndOfSessionWithError: public EndOfSession {
public:
EndOfSessionWithError(std::string w=""):EndOfSession(w) {}
};
private:
/** The VDQM request that kickstarted the session */
......
......@@ -49,10 +49,10 @@ using namespace castor::tape;
//------------------------------------------------------------------------------
ClientSimulator::ClientSimulator(uint32_t volReqId, const std::string & vid,
const std::string & density, tapegateway::ClientType clientType,
tapegateway::VolumeMode volumeMode):
tapegateway::VolumeMode volumeMode, EmptyMount_t emptyMount):
TpcpCommand("clientSimulator::clientSimulator"), m_sessionErrorCode(0),
m_vid(vid), m_density(density), m_clientType(clientType),
m_volumeMode(volumeMode)
m_volumeMode(volumeMode), m_emptyMount(emptyMount)
{
m_volReqId = volReqId;
setupCallbackSock();
......@@ -94,18 +94,27 @@ void ClientSimulator::processFirstRequest()
ex.getMessage() << oss.str();
throw ex;
}
// This should always succeed
tapegateway::VolumeRequest & vReq =
dynamic_cast<tapegateway::VolumeRequest &> (msg);
tapegateway::Volume vol;
vol.setAggregatorTransactionId(vReq.aggregatorTransactionId());
vol.setVid(m_vid);
vol.setClientType(m_clientType);
vol.setMode(m_volumeMode);
vol.setLabel(m_volLabel);
vol.setMountTransactionId(m_volReqId);
vol.setDensity(m_density);
clientConnection->sendObject(vol);
if (EmptyOnVolReq != m_emptyMount) {
tapegateway::Volume vol;
vol.setAggregatorTransactionId(vReq.aggregatorTransactionId());
vol.setVid(m_vid);
vol.setClientType(m_clientType);
vol.setMode(m_volumeMode);
vol.setLabel(m_volLabel);
vol.setMountTransactionId(m_volReqId);
vol.setDensity(m_density);
clientConnection->sendObject(vol);
} else {
tapegateway::NoMoreFiles noMore;
noMore.setAggregatorTransactionId(vReq.aggregatorTransactionId());
noMore.setMountTransactionId(m_volReqId);
clientConnection->sendObject(noMore);
}
}
//------------------------------------------------------------------------------
//processOneRequest
......
......@@ -40,9 +40,14 @@ namespace client {
*/
class ClientSimulator: public tpcp::TpcpCommand {
public:
typedef enum {
NotEmpty,
EmptyOnVolReq,
EmptyOnGetMoreWork
} EmptyMount_t;
ClientSimulator(uint32_t volReqId, const std::string & vid,
const std::string & density, tapegateway::ClientType clientType,
tapegateway::VolumeMode volumeMode);
tapegateway::VolumeMode volumeMode, EmptyMount_t emptyMount = NotEmpty);
virtual ~ClientSimulator() throw() {}
......@@ -142,6 +147,7 @@ namespace client {
std::queue<tapegateway::FileToMigrateStruct> m_filesToMigrate;
const castor::tape::tapegateway::ClientType m_clientType;
const castor::tape::tapegateway::VolumeMode m_volumeMode;
EmptyMount_t m_emptyMount;
};
}
}
......
......@@ -96,18 +96,27 @@ castor::tape::tapeserver::daemon::Session::EndOfSessionAction
client::ClientProxy::RequestReport reqReport;
try {
m_clientProxy.fetchVolumeId(m_volInfo, reqReport);
} catch(client::ClientProxy::EndOfSession & eof) {
} catch(client::ClientProxy::EndOfSessionWithError & eoswe) {
std::stringstream fullError;
fullError << "Received end of session rom client when requesting Volume "
<< eof.getMessageValue();
fullError << "Received end of session with error from client when requesting Volume "
<< eoswe.getMessageValue();
lc.log(LOG_ERR, fullError.str());
m_clientProxy.reportEndOfSession(reqReport);
log::LogContext::ScopedParam sp07(lc, log::Param("tapebridgeTransId", reqReport.transactionId));
log::LogContext::ScopedParam sp08(lc, log::Param("connectDuration", reqReport.connectDuration));
log::LogContext::ScopedParam sp09(lc, log::Param("sendRecvDuration", reqReport.sendRecvDuration));
log::LogContext::ScopedParam sp10(lc, log::Param("ErrorMsg", fullError.str()));
lc.log(LOG_ERR, "Notified client of end session with error");
return MARK_DRIVE_AS_UP;
log::ScopedParamContainer params(lc);
params.add("tapebridgeTransId", reqReport.transactionId)
.add("connectDuration", reqReport.connectDuration)
.add("sendRecvDuration", reqReport.sendRecvDuration);
lc.log(LOG_INFO, "Acknowledged client of end session with error");
return MARK_DRIVE_AS_UP;
} catch(client::ClientProxy::EndOfSession & eos) {
lc.log(LOG_INFO, "Received end of session from client when requesting Volume");
m_clientProxy.reportEndOfSession(reqReport);
log::ScopedParamContainer params(lc);
params.add("tapebridgeTransId", reqReport.transactionId)
.add("connectDuration", reqReport.connectDuration)
.add("sendRecvDuration", reqReport.sendRecvDuration);
lc.log(LOG_INFO, "Acknowledged client of end session");
return MARK_DRIVE_AS_UP;
} catch (client::ClientProxy::UnexpectedResponse & unexp) {
std::stringstream fullError;
fullError << "Received unexpected response from client when requesting Volume"
......
......@@ -431,6 +431,72 @@ TEST(tapeServer, DataTransferSessionFailtoMount) {
ASSERT_EQ(0, sim.m_sessionErrorCode);
}
TEST(tapeServer, DataTransferSessionEmptyOnVolReq) {
// This test is the same as the previous one, with
// wrong parameters set for the recall, so that we fail
// to recall the first file and cancel the second.
castor::log::StringLogger logger("tapeServerUnitTest");
// 1) prepare the client and run it in another thread
uint32_t volReq = 0xBEEF;
std::string vid = "V12345";
std::string density = "8000GC";
client::ClientSimulator sim(volReq, vid, density,
castor::tape::tapegateway::TAPE_GATEWAY,
castor::tape::tapegateway::READ, client::ClientSimulator::EmptyOnVolReq);
client::ClientSimulator::ipPort clientAddr = sim.getCallbackAddress();
clientRunner simRun(sim);
simRun.start();
// 2) Prepare the VDQM request
castor::legacymsg::RtcpJobRqstMsgBody VDQMjob;
snprintf(VDQMjob.clientHost, CA_MAXHOSTNAMELEN+1, "%d.%d.%d.%d",
clientAddr.a, clientAddr.b, clientAddr.c, clientAddr.d);
snprintf(VDQMjob.driveUnit, CA_MAXUNMLEN+1, "T10D6116");
snprintf(VDQMjob.dgn, CA_MAXDGNLEN+1, "LIBXX");
VDQMjob.clientPort = clientAddr.port;
VDQMjob.volReqId = volReq;
// 3) Prepare the necessary environment (logger, plus system wrapper),
// construct and run the session.
castor::tape::System::mockWrapper mockSys;
mockSys.delegateToFake();
mockSys.disableGMockCallsCounting();
mockSys.fake.setupForVirtualDriveSLC6();
// The drive will not even be opened. so no need for one.
mockSys.fake.m_pathToDrive["/dev/nst0"] = NULL;
castor::tape::utils::DriveConfig driveConfig;
driveConfig.unitName = "T10D6116";
driveConfig.dgn = "T10KD6";
driveConfig.devFilename = "/dev/tape_T10D6116";
driveConfig.librarySlot = castor::mediachanger::ConfigLibrarySlot("manual");
DataTransferConfig castorConf;
castorConf.bufsz = 1024*1024; // 1 MB memory buffers
castorConf.nbBufs = 10;
castorConf.bulkRequestRecallMaxBytes = UINT64_C(100)*1000*1000*1000;
castorConf.bulkRequestRecallMaxFiles = 1000;
castorConf.nbDiskThreads = 3;
castor::messages::AcsProxyDummy acs;
castor::mediachanger::MmcProxyDummy mmc;
castor::legacymsg::RmcProxyDummy rmc;
castor::mediachanger::MediaChangerFacade mc(acs, mmc, rmc);
castor::server::ProcessCap capUtils;
castor::messages::TapeserverProxyDummy initialProcess;
DataTransferSession sess("tapeHost", VDQMjob, logger, mockSys,
driveConfig, mc, initialProcess, capUtils, castorConf);
sess.execute();
simRun.wait();
std::string temp = logger.getLog();
temp += "";
ASSERT_EQ("", sess.getVid());
// Currently, failures are reported by files and recall sessions do not fail.
ASSERT_EQ(0, sim.m_sessionErrorCode);
// We should not have logged any error
ASSERT_EQ(std::string::npos, logger.getLog().find("LVL=E"));
}
class tempFile {
public:
tempFile(size_t size): m_size(size) {
......
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