File error_context.cpp¶
File List > base > error_context.cpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* error_context.cpp - implementation for error context
*/
#include "error_context.hpp"
#include "error_code.h"
#include "error_manager.h"
#include "memory_alloc.h"
#if defined (SERVER_MODE)
#include "thread_entry.hpp"
#include "thread_manager.hpp"
#endif // SERVER_MODE
#include <cstring>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
namespace cuberr
{
const bool LOG_ME = false; // todo: set false
// logging macro's. macro's are used instead of inline functions for ARG_FILE_LINE
#define ERROR_CONTEXT_LOG(...) if (m_logging) _er_log_debug (ARG_FILE_LINE, __VA_ARGS__)
#define ERMSG_MSG "{ %p: errid=%d, sev=%d, fname=%s, line=%d, msg_area=%p(%s)_size=%zu, msgbuf=%p(%s), args=%p_n=%d }"
#define ERMSG_ARGS(em) &(em), (em).err_id, (em).severity, (em).file_name, (em).line_no, (em).msg_area, (em).msg_area, \
(em).msg_area_size, (em).msg_buffer, (em).msg_buffer, (em).args, (em).nargs
#define ERMSG_LOG(text, var) ERROR_CONTEXT_LOG (text #var " = " ERMSG_MSG, ERMSG_ARGS (var))
thread_local context *tl_Context_p = NULL;
er_message::er_message (const bool &logging)
: err_id (NO_ERROR)
, severity (ER_WARNING_SEVERITY)
, file_name (NULL)
, line_no (-1)
, msg_area_size (sizeof (msg_buffer))
, msg_area (msg_buffer)
, args (NULL)
, nargs (0)
, msg_buffer {'\0'}
, m_logging (logging)
{
//
}
er_message::~er_message ()
{
ERMSG_LOG ("destruct ", *this);
clear_message_area ();
clear_args ();
}
void er_message::swap (er_message &other)
{
ERMSG_LOG ("before_swap", *this);
ERMSG_LOG ("before_swap", other);
std::swap (this->err_id, other.err_id);
std::swap (this->severity, other.severity);
std::swap (this->file_name, other.file_name);
std::swap (this->line_no, other.line_no);
// msg_area
const std::size_t bufsize = sizeof (this->msg_buffer);
if (this->msg_area_size <= bufsize && other.msg_area_size <= bufsize)
{
assert (this->msg_area_size == bufsize && other.msg_area_size == bufsize);
// swap buffer contexts
char aux_buffer[bufsize];
std::memcpy (aux_buffer, this->msg_buffer, bufsize);
std::memcpy (this->msg_buffer, other.msg_buffer, bufsize);
std::memcpy (other.msg_buffer, aux_buffer, bufsize);
}
else if (this->msg_area_size > bufsize && other.msg_area_size > bufsize)
{
/* swap pointers */
std::swap (this->msg_area, other.msg_area);
std::swap (this->msg_area_size, other.msg_area_size);
}
else if (this->msg_area_size <= bufsize)
{
assert (this->msg_area_size == bufsize);
assert (other.msg_area_size > bufsize);
// copy this buffer to other
std::memcpy (other.msg_buffer, this->msg_buffer, bufsize);
// move msg_area pointer from other to this
this->msg_area = other.msg_area;
other.msg_area = other.msg_buffer;
// swap area size
std::swap (this->msg_area_size, other.msg_area_size);
}
else
{
assert (this->msg_area_size > bufsize);
assert (other.msg_area_size == bufsize);
// copy other buffer to this
std::memcpy (this->msg_buffer, other.msg_buffer, bufsize);
// move msg_area pointer from this to other
other.msg_area = this->msg_area;
this->msg_area = this->msg_buffer;
// swap area size
std::swap (this->msg_area_size, other.msg_area_size);
}
assert ((this->msg_area_size == bufsize) == (this->msg_area == this->msg_buffer));
assert ((other.msg_area_size == bufsize) == (other.msg_area == other.msg_buffer));
assert (this->msg_area != other.msg_area);
// swap args, nargs
std::swap (this->args, other.args);
std::swap (this->nargs, other.nargs);
ERMSG_LOG ("after_swap", *this);
ERMSG_LOG ("after_swap", other);
}
void
er_message::clear_error ()
{
err_id = NO_ERROR;
severity = ER_WARNING_SEVERITY;
file_name = NULL;
line_no = -1;
msg_area[0] = '\0';
}
void
er_message::set_error (int error_id_arg, int error_severity_arg, const char *filename_arg, int line_no_arg)
{
if (error_id_arg >= ER_FAILED || error_id_arg <= ER_LAST_ERROR)
{
assert (false); /* invalid error id */
error_id_arg = ER_FAILED; /* invalid error id handling */
}
err_id = error_id_arg;
severity = error_severity_arg;
file_name = filename_arg;
line_no = line_no_arg;
}
void
er_message::clear_message_area (void)
{
if (msg_area != msg_buffer)
{
delete [] msg_area;
msg_area = msg_buffer;
msg_area_size = sizeof (msg_buffer);
}
}
void
er_message::clear_args (void)
{
if (args != NULL)
{
free_and_init (args);
}
nargs = 0;
}
void
er_message::reserve_message_area (std::size_t size)
{
if (msg_area_size >= size)
{
// no need to resize
return;
}
ERMSG_LOG ("before_resize", *this);
std::size_t new_size = msg_area_size;
while (new_size < size)
{
new_size *= 2;
}
clear_message_area ();
msg_area = new char[new_size];
msg_area_size = new_size;
ERMSG_LOG ("after_resize", *this);
}
context::context (bool automatic_registration, bool logging)
: m_base_level (m_logging)
, m_stack ()
, m_automatic_registration (automatic_registration)
, m_logging (LOG_ME && logging)
, m_destroyed (false)
{
if (automatic_registration)
{
register_thread_local ();
}
}
context::~context (void)
{
// safe-guard: don't destroy twice
assert (!m_destroyed);
m_destroyed = true;
if (tl_Context_p == this)
{
assert (m_automatic_registration);
deregister_thread_local ();
}
}
er_message &
context::get_current_error_level (void)
{
if (m_stack.empty ())
{
return m_base_level;
}
else
{
return m_stack.top ();
}
}
void
context::register_thread_local (void)
{
assert (tl_Context_p == NULL);
tl_Context_p = this;
}
void
context::deregister_thread_local (void)
{
#if defined (SERVER_MODE)
// safe-guard that stacks are not "leaked"
// ignore it for client (this is too late anyway)
assert (m_stack.empty ());
#endif // SERVER_MODE
clear_all_levels ();
assert (tl_Context_p == this);
tl_Context_p = NULL;
}
void
context::clear_current_error_level (void)
{
get_current_error_level ().clear_error ();
}
void
context::push_error_stack (void)
{
m_stack.emplace (m_logging);
}
void
context::pop_error_stack (er_message &popped)
{
if (m_stack.empty ())
{
assert (false);
return;
}
popped.swap (m_stack.top ());
m_stack.pop ();
}
void
context::pop_error_stack_and_destroy (void)
{
er_message temp (m_logging);
pop_error_stack (temp);
// popped memory is freed
}
bool
context::has_error_stack (void)
{
return !m_stack.empty ();
}
const bool &
context::get_logging (void)
{
return m_logging;
}
void
context::clear_all_levels (void)
{
clear_stack ();
m_base_level.clear_error ();
m_base_level.clear_message_area ();
}
void
context::clear_stack (void)
{
// clear stack by swapping; I hope this works
std::stack<er_message> ().swap (m_stack);
}
cuberr::context &
context::get_thread_local_context (void)
{
if (tl_Context_p == NULL)
{
assert (false);
static context emergency_context (false, false);
#if defined (SERVER_MODE)
if (cubthread::get_manager () != NULL)
{
return cubthread::get_entry ().get_error_context ();
}
#endif // SERVER_MODE
return emergency_context;
}
return *tl_Context_p;
}
er_message &
context::get_thread_local_error (void)
{
return get_thread_local_context ().get_current_error_level ();
}
} // namespace cuberr