Commit 68882e02 authored by Eric Cano's avatar Eric Cano
Browse files

Added a SCSI::Exception class, which automatically turns status/sense data into loggable strings.

Added an exception launcher function to prevent repetive tests.
Clarified the error/exception handling strategy in the manual.
parent 6e8533ae
......@@ -239,7 +239,7 @@ namespace SCSI {
\end{lstlisting}
\end{table}
\subsection{Exceptions hierarchy}
\subsection{Exceptions hierarchy and error handling strategy}
There is a small class hierarchy for exceptions: \verb#Tape::Exception# inherits from
\verb#std::exception#, and \verb#Tape::Exceptions::Errnum# inherits from the latter.
......@@ -247,6 +247,22 @@ There is a small class hierarchy for exceptions: \verb#Tape::Exception# inherits
into a string automatically at construction time. \verb#Tape::Exception# and all inheriting
classes collect a stack trace at construction time.
\verb#Tape::Exception# and all its heirs automatically generate a stack trace at creation time.
This allows easy tracing of unhandled exceptions, as the stack trace embedded in the content
of the \verb#what()# method. For the cases where the exception is indeed handled, a shorter version
called \verb#shortWhat()# allows the logging of the problem without bloating the logs with long stack
traces.
Another exception class, \verb#SCSI::Exception#, turns the SCSI status and sense buffer into a
user readable string.
Throughout the project, the error handling strategy is to throw an exception when any
error condition occurs. This ensures that any returned value is valid, and prevents the
calling function from testing for error conditions. The default exception throwing is
coming from a narrow set of exceptions types. This gives a crude exception handling capacity
to the user of the functions. When finer grained exceptions will turn out to be required,
we will add them on an as needed basis.
\subsection{The Tape::Drive object}
This first deliverable is a tape drive object. This tape drive object abstracts all
......
......@@ -25,6 +25,7 @@
#include "../SCSI/Device.hh"
#include "../SCSI/Structures.hh"
#include "../SCSI/Exception.hh"
#include "../System/Wrapper.hh"
#include "../Exception/Exception.hh"
......@@ -146,9 +147,7 @@ namespace Tape {
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in clearCompressionStats: ") +
SCSI::statusToString(sgh.status));
SCSI::ExceptionLauncher(sgh, "SCSI error in clearCompressionStats:");
}
/**
......@@ -181,9 +180,7 @@ namespace Tape {
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in positionToLogicalObject: ") +
SCSI::statusToString(sgh.status));
SCSI::ExceptionLauncher(sgh, "SCSI error in positionToLogicalObject:");
}
......@@ -210,8 +207,7 @@ namespace Tape {
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in getPositionInfo: ") +
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getPositionInfo: ") +
SCSI::statusToString(sgh.status));
if ( 0 == positionData.PERR ) { // Location fields are valid
......@@ -254,8 +250,7 @@ namespace Tape {
/* Manage both system error and SCSI errors. */
if (-1 == m_sysWrapper.ioctl(m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in getTapeAlerts: ") +
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getTapeAlerts: ") +
SCSI::statusToString(sgh.status));
/* Return the ACTIVE tape alerts (this is indicated by "flag" (see
* SSC-4: 8.2.3 TapeAlert log page). As they are simply used for logging;
......@@ -395,8 +390,7 @@ class DriveT10000 : public Drive<sysWrapperClass> {
/* Manage both system error and SCSI errors. */
if (-1 == this->m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in getCompression: ") +
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getCompression: ") +
SCSI::statusToString(sgh.status));
SCSI::Structures::logSenseLogPageHeader_t & logPageHeader =
......@@ -458,8 +452,7 @@ class DriveLTO : public Drive<sysWrapperClass> {
/* Manage both system error and SCSI errors. */
if (-1 == this->m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in getCompression: ") +
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getCompression: ") +
SCSI::statusToString(sgh.status));
SCSI::Structures::logSenseLogPageHeader_t & logPageHeader =
......@@ -540,8 +533,7 @@ class DriveIBM3592 : public Drive<sysWrapperClass> {
/* Manage both system error and SCSI errors. */
if (-1 == this->m_sysWrapper.ioctl(this->m_tapeFD, SG_IO, &sgh))
throw Tape::Exceptions::Errnum("Failed SG_IO ioctl");
if (SCSI::Status::GOOD != sgh.status)
throw Tape::Exception(std::string("SCSI error in getCompression: ") +
SCSI::ExceptionLauncher(sgh, std::string("SCSI error in getCompression: ") +
SCSI::statusToString(sgh.status));
SCSI::Structures::logSenseLogPageHeader_t & logPageHeader =
......
......@@ -40,10 +40,15 @@ const char * Tape::Exception::what() const throw () {
return m_what.c_str();
}
const char * Tape::Exception::shortWhat() const throw () {
return m_shortWhat.c_str();
}
void Tape::Exception::setWhat(const std::string& what) {
std::stringstream w;
w << what << std::endl << std::string(backtrace);
m_what = w.str();
m_shortWhat = what;
}
Tape::Exceptions::Errnum::Errnum(std::string what):Exception("") {
......
......@@ -39,14 +39,16 @@ namespace Tape {
class Exception: public std::exception {
public:
Exception(const std::string& what): m_what(what) {};
Exception(const std::string& what) { setWhat(what); }
virtual ~Exception() throw() {};
virtual const char * what() const throw();
virtual const char * shortWhat() const throw();
Tape::Exceptions::Backtrace backtrace;
protected:
void setWhat(const std::string &w);
private:
std::string m_what;
std::string m_shortWhat;
};
namespace Exceptions {
......
......@@ -58,6 +58,9 @@ namespace UnitTests {
std::string bt = e.backtrace;
ASSERT_NE(std::string::npos, bt.find("Nested::f1"));
ASSERT_NE(std::string::npos, bt.find("Tape::Exceptions::Backtrace::Backtrace"));
ASSERT_EQ("", std::string(e.shortWhat()));
std::string fullWhat(e.what());
ASSERT_NE(std::string::npos, fullWhat.find("Nested::f1"));
}
}
......
add_library(SCSI Device.cc Structures.cc Constants.cc)
add_library(SCSI Device.cc Structures.cc Constants.cc Exception.cc)
#add_executable(SCSIDumpTest DumpTest.cc)
#target_link_libraries(SCSIDumpTest SCSI)
......@@ -218,7 +218,7 @@ namespace SCSI {
TASK_SET_FULL = 0x28,
ACA_ACTIVE = 0x30,
TASK_ABORTED = 0x40
};
} Status_t;
};
/**
......
......@@ -26,6 +26,7 @@
#include "Device.hh"
#include "Structures.hh"
#include "../System/Wrapper.hh"
#include "Exception.hh"
using ::testing::AtLeast;
using ::testing::Return;
......@@ -460,4 +461,26 @@ namespace UnitTests {
unsigned char num[8] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xFA, 0xDE };
ASSERT_EQ ( 0xDEADBEEFCAFEFADEULL, SCSI::Structures::toU64(num));
}
TEST(SCSI_Strucutres, Exception) {
SCSI::Structures::senseData_t<255> sense;
SCSI::Structures::LinuxSGIO_t sgio;
sgio.setSenseBuffer(&sense);
sgio.status = SCSI::Status::GOOD;
ASSERT_NO_THROW(SCSI::ExceptionLauncher(sgio));
sgio.status = SCSI::Status::CHECK_CONDITION;
/* fill up the ASC part of the */
sense.responseCode = 0x70;
sense.fixedFormat.ASC = 0x14;
sense.fixedFormat.ASCQ = 0x04;
ASSERT_THROW(SCSI::ExceptionLauncher(sgio), SCSI::Exception);
try { SCSI::ExceptionLauncher(sgio, "In exception validation:"); }
catch (SCSI::Exception & ex) {
std::string what(ex.shortWhat());
ASSERT_NE(std::string::npos, what.find("Block sequence error"));
/* We check here that the formatting is also done correctly (space added when context
not empty */
ASSERT_NE(std::string::npos, what.find("In exception validation: "));
}
}
};
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