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

Mergind master into rao_branch

parents 12529714 ce4a27cf
......@@ -259,17 +259,12 @@ public:
/**
* Creates a tape which is assumed to have logical block protection (LBP)
* enabled.
*
* @param encryptionKey The optional identifier of the encrption key. This
* optional parameter should either have a non-empty string value or no value
* at all. Empty strings are prohibited.
*/
virtual void createTape(
const common::dataStructures::SecurityIdentity &admin,
const std::string &vid,
const std::string &logicalLibraryName,
const std::string &tapePoolName,
const optional<std::string> &encryptionKey,
const uint64_t capacityInBytes,
const bool disabled,
const bool full,
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#include "common/exception/UserError.hpp"
#include "common/exception/Exception.hpp"
#include "common/make_unique.hpp"
#include "common/threading/MutexLocker.hpp"
#include "common/utils/utils.hpp"
#include "rdbms/AutoRollback.hpp"
#include "rdbms/ConnFactoryFactory.hpp"
......@@ -293,7 +294,7 @@ void OracleCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
const auto &firstEvent = *firstEventItor;
checkTapeFileWrittenFieldsAreSet(firstEvent);
const time_t now = time(nullptr);
std::lock_guard<std::mutex> m_lock(m_mutex);
threading::MutexLocker locker(m_mutex);
auto conn = m_connPool.getConn();
rdbms::AutoRollback autoRollback(conn);
......
......@@ -23,6 +23,7 @@
#include "common/exception/Exception.hpp"
#include "common/exception/UserError.hpp"
#include "common/make_unique.hpp"
#include "common/threading/MutexLocker.hpp"
#include "common/utils/utils.hpp"
#include "rdbms/AutoRollback.hpp"
......@@ -1526,17 +1527,11 @@ void RdbmsCatalogue::createTape(
const std::string &vid,
const std::string &logicalLibraryName,
const std::string &tapePoolName,
const optional<std::string> &encryptionKey,
const uint64_t capacityInBytes,
const bool disabled,
const bool full,
const std::string &comment) {
try {
if(encryptionKey && encryptionKey.value().empty()) {
throw(exception::Exception(std::string("The identifier of the encrption key for tape ") + vid + " has been set "
"to the empty string. This optional value should either have a non-empty string value or no value at all"));
}
auto conn = m_connPool.getConn();
if(tapeExists(conn, vid)) {
throw exception::UserError(std::string("Cannot create tape ") + vid +
......@@ -1556,7 +1551,6 @@ void RdbmsCatalogue::createTape(
"VID,"
"LOGICAL_LIBRARY_NAME,"
"TAPE_POOL_NAME,"
"ENCRYPTION_KEY,"
"CAPACITY_IN_BYTES,"
"DATA_IN_BYTES,"
"LAST_FSEQ,"
......@@ -1576,7 +1570,6 @@ void RdbmsCatalogue::createTape(
":VID,"
":LOGICAL_LIBRARY_NAME,"
":TAPE_POOL_NAME,"
":ENCRYPTION_KEY,"
":CAPACITY_IN_BYTES,"
":DATA_IN_BYTES,"
":LAST_FSEQ,"
......@@ -1597,7 +1590,6 @@ void RdbmsCatalogue::createTape(
stmt->bindString(":VID", vid);
stmt->bindString(":LOGICAL_LIBRARY_NAME", logicalLibraryName);
stmt->bindString(":TAPE_POOL_NAME", tapePoolName);
stmt->bindOptionalString(":ENCRYPTION_KEY", encryptionKey);
stmt->bindUint64(":CAPACITY_IN_BYTES", capacityInBytes);
stmt->bindUint64(":DATA_IN_BYTES", 0);
stmt->bindUint64(":LAST_FSEQ", 0);
......@@ -4453,7 +4445,7 @@ void RdbmsCatalogue::insertTapeFile(
//------------------------------------------------------------------------------
void RdbmsCatalogue::setTapeLastFSeq(rdbms::PooledConn &conn, const std::string &vid, const uint64_t lastFSeq) {
try {
std::lock_guard<std::mutex> lock(m_mutex);
threading::MutexLocker locker(m_mutex);
const uint64_t currentValue = getTapeLastFSeq(conn, vid);
if(lastFSeq != currentValue + 1) {
......
......@@ -20,11 +20,11 @@
#include "catalogue/Catalogue.hpp"
#include "catalogue/RequesterAndGroupMountPolicies.hpp"
#include "common/threading/Mutex.hpp"
#include "rdbms/Conn.hpp"
#include "rdbms/ConnPool.hpp"
#include <memory>
#include <mutex>
namespace cta {
namespace common {
......@@ -240,17 +240,12 @@ public:
/**
* Creates a tape.
*
* @param encryptionKey The optional identifier of the encrption key. This
* optional parameter should either have a non-empty string value or no value
* at all. Empty strings are prohibited.
*/
void createTape(
const common::dataStructures::SecurityIdentity &admin,
const std::string &vid,
const std::string &logicalLibraryName,
const std::string &tapePoolName,
const optional<std::string> &encryptionKey,
const uint64_t capacityInBytes,
const bool disabled,
const bool full,
......@@ -502,7 +497,7 @@ protected:
/**
* Mutex to be used to a take a global lock on the database.
*/
std::mutex m_mutex;
threading::Mutex m_mutex;
/**
* The database connection factory.
......
......@@ -22,6 +22,7 @@
#include "common/exception/Exception.hpp"
#include "common/exception/UserError.hpp"
#include "common/make_unique.hpp"
#include "common/threading/MutexLocker.hpp"
#include "common/utils/utils.hpp"
#include "rdbms/AutoRollback.hpp"
#include "rdbms/ConnFactoryFactory.hpp"
......@@ -100,7 +101,7 @@ uint64_t SqliteCatalogue::getNextArchiveFileId(rdbms::PooledConn &conn) {
try {
// The SQLite implemenation of getNextArchiveFileId() serializes access to
// the SQLite database in order to avoid busy errors
std::lock_guard<std::mutex> m_lock(m_mutex);
threading::MutexLocker locker(m_mutex);
rdbms::AutoRollback autoRollback(conn);
......@@ -243,7 +244,7 @@ void SqliteCatalogue::filesWrittenToTape(const std::set<TapeFileWritten> &events
// Given the above assumption regarding the laws of physics, a simple lock
// on the mutex of the SqliteCatalogue object is enough to emulate an
// Oracle SELECT FOR UPDATE
std::lock_guard<std::mutex> m_lock(m_mutex);
threading::MutexLocker locker(m_mutex);
auto conn = m_connPool.getConn();
const auto tape = selectTape(rdbms::Stmt::AutocommitMode::ON, conn, firstEvent.vid);
......
......@@ -176,3 +176,5 @@ add_library (ctacommonunittests SHARED
install(TARGETS ctacommonunittests DESTINATION usr/${CMAKE_INSTALL_LIBDIR})
add_executable(mutexLtrace threading/MutexLtrace.cpp)
target_link_libraries (mutexLtrace ctacommon)
......@@ -40,9 +40,11 @@ DummyLogger::~DummyLogger() {
void DummyLogger::prepareForFork() {}
//------------------------------------------------------------------------------
// reducedSyslog
// writeMsgToUnderlyingLoggingSystem
//------------------------------------------------------------------------------
void DummyLogger::reducedSyslog(const std::string & msg) {}
void DummyLogger::writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) {
// Do nothing
}
} // namespace log
} // namespace cta
......@@ -57,7 +57,23 @@ public:
void prepareForFork() ;
protected:
virtual void reducedSyslog(const std::string & msg);
/**
* Writes the specified msg to the underlying logging system.
*
* This method is to be implemented by concrete sub-classes of the Logger
* class.
*
* Please note it is the responsibility of a concrete sub-class to decide
* whether or not to use the specified log message header. For example, the
* SysLogLogger sub-class does not use the header. Instead it relies on
* rsyslog to provide a header.
*
* @param header The header of the message to be logged. It is the
* esponsibility of the concrete sub-class
* @param body The body of the message to be logged.
*/
void writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) override;
}; // class DummyLogger
......
......@@ -54,21 +54,24 @@ void FileLogger::prepareForFork() {
}
//-----------------------------------------------------------------------------
// reducedSyslog
// writeMsgToUnderlyingLoggingSystem
//-----------------------------------------------------------------------------
void FileLogger::reducedSyslog(const std::string & msg) {
void FileLogger::writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) {
if (-1 == m_fd)
throw cta::exception::Exception("In FileLogger::reducedSyslog(): file is not properly initialized");
throw cta::exception::Exception("In FileLogger::writeMsgToUnderlyingLoggingSystem(): file is not properly initialized");
const std::string headerPlusBody = header + body;
// Prepare the string to print (for size)
std::string m = msg.substr(0, m_maxMsgLen) + "\n";
std::string m = headerPlusBody.substr(0, m_maxMsgLen) + "\n";
// enter critical section
threading::MutexLocker lock(m_mutex);
// Append the message to the file
cta::exception::Errnum::throwOnMinusOne(::write(m_fd, m.c_str(), m.size()),
"In FileLogger::reducedSyslog(): failed to write to file");
"In FileLogger::writeMsgToUnderlyingLoggingSystem(): failed to write to file");
}
} // namespace log
} // namespace cta
\ No newline at end of file
} // namespace cta
......@@ -68,15 +68,21 @@ protected:
int m_fd=-1;
/**
* A reduced version of syslog. This method is able to set the message
* timestamp. This is necessary when logging messages asynchronously of there
* creation, such as when retrieving logs from the DB. This function truncates
* the message if necessary. It also adds a new line at the end of the message
* if needed.
* Writes the specified msg to the underlying logging system.
*
* @param msg The message to be logged.
* This method is to be implemented by concrete sub-classes of the Logger
* class.
*
* Please note it is the responsibility of a concrete sub-class to decide
* whether or not to use the specified log message header. For example, the
* SysLogLogger sub-class does not use the header. Instead it relies on
* rsyslog to provide a header.
*
* @param header The header of the message to be logged. It is the
* esponsibility of the concrete sub-class
* @param body The body of the message to be logged.
*/
void reducedSyslog(const std::string & msg);
void writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) override;
}; // class StringLogger
......
......@@ -61,14 +61,6 @@ void Logger::operator() (
gettimeofday(&timeStamp, NULL);
const int pid = getpid();
//-------------------------------------------------------------------------
// Note that we do here part of the work of the real syslog call, by
// building the message ourselves. We then only call a reduced version of
// syslog (namely reducedSyslog). The reason behind it is to be able to set
// the message timestamp ourselves, in case we log messages asynchronously,
// as we do when retrieving logs from the DB
//-------------------------------------------------------------------------
// Ignore messages whose priority is not of interest
if(priority > m_logMask) {
return;
......@@ -86,102 +78,10 @@ void Logger::operator() (
// Safe to get a reference to the textual representation of the priority
const std::string &priorityText = priorityTextPair->second;
std::ostringstream os;
writeLogMsg(
os,
priority,
priorityText,
msg,
params,
rawParams,
timeStamp,
m_programName,
pid);
reducedSyslog(os.str());
}
//-----------------------------------------------------------------------------
// writeLogMsg
//-----------------------------------------------------------------------------
void Logger::writeLogMsg(
std::ostringstream &os,
const int priority,
const std::string &priorityText,
const std::string &msg,
const std::list<Param> &params,
const std::string &rawParams,
const struct timeval &timeStamp,
const std::string &programName,
const int pid) {
//-------------------------------------------------------------------------
// Note that we do here part of the work of the real syslog call, by
// building the message ourselves. We then only call a reduced version of
// syslog (namely reducedSyslog). The reason behind it is to be able to set
// the message timestamp ourselves, in case we log messages asynchronously,
// as we do when retrieving logs from the DB
//-------------------------------------------------------------------------
// Start message with priority, time, program and PID (syslog standard
// format)
writeHeader(os, priority | LOG_LOCAL3, timeStamp, programName, pid);
const int tid = syscall(__NR_gettid);
// Append the log level, the thread id and the message text
os << "LVL=\"" << priorityText << "\" TID=\"" << tid << "\" MSG=\"" <<
msg << "\" ";
// Process parameters
for(auto itor = params.cbegin(); itor != params.cend(); itor++) {
const Param &param = *itor;
// Check the parameter name, if it's an empty string set the value to
// "Undefined".
const std::string name = param.getName() == "" ? "Undefined" :
cleanString(param.getName(), true);
// Process the parameter value
const std::string value = cleanString(param.getValue(), false);
// Write the name and value to the buffer
os << name << "=\"" << value << "\" ";
}
const std::string header = createMsgHeader(timeStamp, m_programName, pid);
const std::string body = createMsgBody(priority, priorityText, msg, params, rawParams, m_programName, pid);
// Append raw parameters
os << rawParams;
}
//-----------------------------------------------------------------------------
// writeHeader
//-----------------------------------------------------------------------------
void Logger::writeHeader(
std::ostringstream &os,
const int priority,
const struct timeval &timeStamp,
const std::string &programName,
const int pid) {
char buf[80];
int bufLen = sizeof(buf);
int len = 0;
os << "<" << priority << ">";
struct tm localTime;
localtime_r(&(timeStamp.tv_sec), &localTime);
len += strftime(buf, bufLen, "%Y-%m-%dT%T", &localTime);
len += snprintf(buf + len, bufLen - len, ".%06ld",
(unsigned long)timeStamp.tv_usec);
len += strftime(buf + len, bufLen - len, "%z: ", &localTime);
// dirty trick to have the proper timezone format (':' between hh and mm)
buf[len-2] = buf[len-3];
buf[len-3] = buf[len-4];
buf[len-4] = ':';
buf[sizeof(buf) - 1] = '\0';
os << buf << programName << "[" << pid << "]: ";
writeMsgToUnderlyingLoggingSystem(header, body);
}
//-----------------------------------------------------------------------------
......@@ -323,5 +223,73 @@ void Logger::setLogMask(const int logMask) {
m_logMask = logMask;
}
//-----------------------------------------------------------------------------
// createMsgHeader
//-----------------------------------------------------------------------------
std::string Logger::createMsgHeader(
const struct timeval &timeStamp,
const std::string &programName,
const int pid) {
std::ostringstream os;
char buf[80];
int bufLen = sizeof(buf);
int len = 0;
struct tm localTime;
localtime_r(&(timeStamp.tv_sec), &localTime);
len += strftime(buf, bufLen, "%Y-%m-%dT%T", &localTime);
len += snprintf(buf + len, bufLen - len, ".%06ld",
(unsigned long)timeStamp.tv_usec);
len += strftime(buf + len, bufLen - len, "%z: ", &localTime);
// dirty trick to have the proper timezone format (':' between hh and mm)
buf[len-2] = buf[len-3];
buf[len-3] = buf[len-4];
buf[len-4] = ':';
buf[sizeof(buf) - 1] = '\0';
os << buf << programName << "[" << pid << "]: ";
return os.str();
}
//-----------------------------------------------------------------------------
// createMsgBody
//-----------------------------------------------------------------------------
std::string Logger::createMsgBody(
const int priority,
const std::string &priorityText,
const std::string &msg,
const std::list<Param> &params,
const std::string &rawParams,
const std::string &programName,
const int pid) {
std::ostringstream os;
const int tid = syscall(__NR_gettid);
// Append the log level, the thread id and the message text
os << "LVL=\"" << priorityText << "\" PID=\"" << pid << "\" TID=\"" << tid << "\" MSG=\"" <<
msg << "\" ";
// Process parameters
for(auto itor = params.cbegin(); itor != params.cend(); itor++) {
const Param &param = *itor;
// Check the parameter name, if it's an empty string set the value to
// "Undefined".
const std::string name = param.getName() == "" ? "Undefined" :
cleanString(param.getName(), true);
// Process the parameter value
const std::string value = cleanString(param.getValue(), false);
// Write the name and value to the buffer
os << name << "=\"" << value << "\" ";
}
// Append raw parameters
os << rawParams;
return os.str();
}
} // namespace log
} // namespace cta
......@@ -109,8 +109,7 @@ public:
virtual void prepareForFork() = 0;
/**
* Returns the name of the program that is to be prepended to every log
* message.
* Returns the name of the program.
*/
const std::string &getProgramName() const;
......@@ -144,23 +143,6 @@ public:
* @param logMask The log mask.
*/
void setLogMask(const int logMask);
/**
* Writes the header of a syslog message to teh specifed output stream.
*
* @param os The output stream to which the header will be written.
* @param priority The priority of the message.
* @param timeStamp The time stamp of the message.
* @param programName the program name of the log message.
* @param pid The process ID of the process logging the message.
* @return The header of the syslog message.
*/
static void writeHeader(
std::ostringstream &os,
const int priority,
const struct timeval &timeStamp,
const std::string &programName,
const int pid);
/**
* Creates a clean version of the specified string ready for use with syslog.
......@@ -181,13 +163,21 @@ protected:
const std::string m_programName;
/**
* A reduced version of syslog. This method is able to set the message
* timestamp. This is necessary when logging messages asynchronously of there
* creation, such as when retrieving logs from the DB.
* Writes the specified msg to the underlying logging system.
*
* @param msg The message to be logged.
* This method is to be implemented by concrete sub-classes of the Logger
* class.
*
* Please note it is the responsibility of a concrete sub-class to decide
* whether or not to use the specified log message header. For example, the
* SysLogLogger sub-class does not use the header. Instead it relies on
* rsyslog to provide a header.
*
* @param header The header of the message to be logged. It is the
* esponsibility of the concrete sub-class
* @param body The body of the message to be logged.
*/
virtual void reducedSyslog(const std::string & msg) = 0;
virtual void writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) = 0;
/**
* The log mask.
......@@ -209,29 +199,6 @@ protected:
* their equivalent syslog priorities.
*/
const std::map<std::string, int> m_configTextToPriority;
/**
* Writes a log message to the specified output stream.
*
* @param logMsg The output stream to which the log message is to be written.
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param params the parameters of the message.
* @param rawParams preprocessed parameters of the message.
* @param timeStamp the time stamp of the log message.
* @param programName the program name of the log message.
* @param pid the pid of the log message.
*/
static void writeLogMsg(
std::ostringstream &os,
const int priority,
const std::string &priorityText,
const std::string &msg,
const std::list<Param> &params,
const std::string &rawParams,
const struct timeval &timeStamp,
const std::string &programName,
const int pid);
/**
* Default size of a syslog message.
......@@ -269,6 +236,45 @@ protected:
*/
static std::map<std::string, int> generateConfigTextToPriorityMap();
private:
/**
* Creates and returns the header of a log message.
*
* Concrete subclasses of the Logger class can decide whether or not to use
* message headers created by this method. The SysLogger sub-class for example
* relies on rsyslog to provide message headers and therefore does not call
* this method.
*
* @param timeStamp The time stamp of the message.
* @param programName the program name of the log message.
* @param pid The process ID of the process logging the message.
* @return The message header.
*/
static std::string createMsgHeader(
const struct timeval &timeStamp,
const std::string &programName,
const int pid);
/**
* Creates and returns the body of a log message.
*
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param params the parameters of the message.
* @param rawParams preprocessed parameters of the message.
* @param programName the program name of the log message.
* @param pid the pid of the log message.
* @return The message body;
*/
static std::string createMsgBody(
const int priority,
const std::string &priorityText,
const std::string &msg,
const std::list<Param> &params,
const std::string &rawParams,
const std::string &programName,
const int pid);
}; // class Logger
......
......@@ -40,11 +40,12 @@ StdoutLogger::~StdoutLogger() {
void StdoutLogger::prepareForFork() {}
//------------------------------------------------------------------------------
// reducedSyslog
// writeMsgToUnderlyingLoggingSystem
//------------------------------------------------------------------------------
void StdoutLogger::reducedSyslog(const std::string & msg) {
printf("%s\n", msg.c_str());
void StdoutLogger::writeMsgToUnderlyingLoggingSystem(const std::string &header, const std::string &body) {
const std::string headerPlusBody = header + body;
printf("%s\n", headerPlusBody.c_str());
}
}