CUBRID Engine  latest
error_context.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * error_context.cpp - implementation for error context
21  */
22 
23 #include "error_context.hpp"
24 
25 #include "error_code.h"
26 #include "error_manager.h"
27 #include "memory_alloc.h"
28 #if defined (SERVER_MODE)
29 #include "thread_entry.hpp"
30 #include "thread_manager.hpp"
31 #endif // SERVER_MODE
32 
33 #include <cstring>
34 
35 namespace cuberr
36 {
37  const bool LOG_ME = false; // todo: set false
38 
39  // logging macro's. macro's are used instead of inline functions for ARG_FILE_LINE
40 #define ERROR_CONTEXT_LOG(...) if (m_logging) _er_log_debug (ARG_FILE_LINE, __VA_ARGS__)
41 
42 #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 }"
43 #define ERMSG_ARGS(em) &(em), (em).err_id, (em).severity, (em).file_name, (em).line_no, (em).msg_area, (em).msg_area, \
44  (em).msg_area_size, (em).msg_buffer, (em).msg_buffer, (em).args, (em).nargs
45 #define ERMSG_LOG(text, var) ERROR_CONTEXT_LOG (text #var " = " ERMSG_MSG, ERMSG_ARGS (var))
46 
47  thread_local context *tl_Context_p = NULL;
48 
49  er_message::er_message (const bool &logging)
50  : err_id (NO_ERROR)
51  , severity (ER_WARNING_SEVERITY)
52  , file_name (NULL)
53  , line_no (-1)
54  , msg_area_size (sizeof (msg_buffer))
55  , msg_area (msg_buffer)
56  , args (NULL)
57  , nargs (0)
58  , msg_buffer {'\0'}
59  , m_logging (logging)
60  {
61  //
62  }
63 
65  {
66  ERMSG_LOG ("destruct ", *this);
68  clear_args ();
69  }
70 
72  {
73  ERMSG_LOG ("before_swap", *this);
74  ERMSG_LOG ("before_swap", other);
75 
76  std::swap (this->err_id, other.err_id);
77  std::swap (this->severity, other.severity);
78  std::swap (this->file_name, other.file_name);
79  std::swap (this->line_no, other.line_no);
80 
81  // msg_area
82  const std::size_t bufsize = sizeof (this->msg_buffer);
83  if (this->msg_area_size <= bufsize && other.msg_area_size <= bufsize)
84  {
85  assert (this->msg_area_size == bufsize && other.msg_area_size == bufsize);
86 
87  // swap buffer contexts
88  char aux_buffer[bufsize];
89  std::memcpy (aux_buffer, this->msg_buffer, bufsize);
90  std::memcpy (this->msg_buffer, other.msg_buffer, bufsize);
91  std::memcpy (other.msg_buffer, aux_buffer, bufsize);
92  }
93  else if (this->msg_area_size > bufsize && other.msg_area_size > bufsize)
94  {
95  /* swap pointers */
96  std::swap (this->msg_area, other.msg_area);
97  std::swap (this->msg_area_size, other.msg_area_size);
98  }
99  else if (this->msg_area_size <= bufsize)
100  {
101  assert (this->msg_area_size == bufsize);
102  assert (other.msg_area_size > bufsize);
103 
104  // copy this buffer to other
105  std::memcpy (other.msg_buffer, this->msg_buffer, bufsize);
106  // move msg_area pointer from other to this
107  this->msg_area = other.msg_area;
108  other.msg_area = other.msg_buffer;
109  // swap area size
110  std::swap (this->msg_area_size, other.msg_area_size);
111  }
112  else
113  {
114  assert (this->msg_area_size > bufsize);
115  assert (other.msg_area_size == bufsize);
116 
117  // copy other buffer to this
118  std::memcpy (this->msg_buffer, other.msg_buffer, bufsize);
119  // move msg_area pointer from this to other
120  other.msg_area = this->msg_area;
121  this->msg_area = this->msg_buffer;
122  // swap area size
123  std::swap (this->msg_area_size, other.msg_area_size);
124  }
125 
126  assert ((this->msg_area_size == bufsize) == (this->msg_area == this->msg_buffer));
127  assert ((other.msg_area_size == bufsize) == (other.msg_area == other.msg_buffer));
128  assert (this->msg_area != other.msg_area);
129 
130  // swap args, nargs
131  std::swap (this->args, other.args);
132  std::swap (this->nargs, other.nargs);
133 
134  ERMSG_LOG ("after_swap", *this);
135  ERMSG_LOG ("after_swap", other);
136  }
137 
138  void
140  {
141  err_id = NO_ERROR;
143  file_name = NULL;
144  line_no = -1;
145  msg_area[0] = '\0';
146  }
147 
148  void
149  er_message::set_error (int error_id_arg, int error_severity_arg, const char *filename_arg, int line_no_arg)
150  {
151  if (error_id_arg >= ER_FAILED || error_id_arg <= ER_LAST_ERROR)
152  {
153  assert (false); /* invalid error id */
154  error_id_arg = ER_FAILED; /* invalid error id handling */
155  }
156  err_id = error_id_arg;
157  severity = error_severity_arg;
158  file_name = filename_arg;
159  line_no = line_no_arg;
160  }
161 
162  void
164  {
165  if (msg_area != msg_buffer)
166  {
167  delete [] msg_area;
168 
170  msg_area_size = sizeof (msg_buffer);
171  }
172  }
173 
174  void
176  {
177  if (args != NULL)
178  {
180  }
181  nargs = 0;
182  }
183 
184  void
186  {
187  if (msg_area_size >= size)
188  {
189  // no need to resize
190  return;
191  }
192 
193  ERMSG_LOG ("before_resize", *this);
194 
195  std::size_t new_size = msg_area_size;
196  while (new_size < size)
197  {
198  new_size *= 2;
199  }
201 
202  msg_area = new char[new_size];
203  msg_area_size = new_size;
204 
205  ERMSG_LOG ("after_resize", *this);
206  }
207 
208  context::context (bool automatic_registration, bool logging)
209  : m_base_level (m_logging)
210  , m_stack ()
211  , m_automatic_registration (automatic_registration)
212  , m_logging (LOG_ME && logging)
213  , m_destroyed (false)
214  {
215  if (automatic_registration)
216  {
218  }
219  }
220 
222  {
223  // safe-guard: don't destroy twice
224  assert (!m_destroyed);
225  m_destroyed = true;
226 
227  if (tl_Context_p == this)
228  {
231  }
232  }
233 
234  er_message &
236  {
237  if (m_stack.empty ())
238  {
239  return m_base_level;
240  }
241  else
242  {
243  return m_stack.top ();
244  }
245  }
246 
247  void
249  {
250  assert (tl_Context_p == NULL);
251  tl_Context_p = this;
252  }
253 
254  void
256  {
257 #if defined (SERVER_MODE)
258  // safe-guard that stacks are not "leaked"
259  // ignore it for client (this is too late anyway)
260  assert (m_stack.empty ());
261 #endif // SERVER_MODE
262 
263  clear_all_levels ();
264 
265  assert (tl_Context_p == this);
266  tl_Context_p = NULL;
267  }
268 
269  void
271  {
273  }
274 
275  void
277  {
278  m_stack.emplace (m_logging);
279  }
280 
281  void
283  {
284  if (m_stack.empty ())
285  {
286  assert (false);
287  return;
288  }
289  popped.swap (m_stack.top ());
290  m_stack.pop ();
291  }
292 
293  void
295  {
296  er_message temp (m_logging);
297  pop_error_stack (temp);
298 
299  // popped memory is freed
300  }
301 
302  bool
304  {
305  return !m_stack.empty ();
306  }
307 
308  const bool &
310  {
311  return m_logging;
312  }
313 
314  void
316  {
317  clear_stack ();
320  }
321 
322  void
324  {
325  // clear stack by swapping; I hope this works
326  std::stack<er_message> ().swap (m_stack);
327  }
328 
331  {
332  if (tl_Context_p == NULL)
333  {
334  assert (false);
335  static context emergency_context (false, false);
336 #if defined (SERVER_MODE)
337  if (cubthread::get_manager () != NULL)
338  {
340  }
341 #endif // SERVER_MODE
342  return emergency_context;
343  }
344  return *tl_Context_p;
345  }
346 
347  er_message &
349  {
351  }
352 
353 
354 } // namespace cuberr
#define NO_ERROR
Definition: error_code.h:46
char msg_buffer[ER_EMERGENCY_BUF_SIZE]
#define ER_FAILED
Definition: error_code.h:47
context(bool automatic_registration=false, bool logging=false)
void clear_message_area(void)
er_message & get_current_error_level(void)
thread_local context * tl_Context_p
er_message m_base_level
void pop_error_stack_and_destroy(void)
void register_thread_local(void)
void pop_error_stack(er_message &popped)
#define ERMSG_LOG(text, var)
manager * get_manager(void)
std::stack< er_message > m_stack
#define assert(x)
void clear_stack(void)
void clear_current_error_level(void)
const bool & m_logging
cuberr::context & get_error_context(void)
static er_message & get_thread_local_error(void)
void swap(er_message &other)
#define NULL
Definition: freelistheap.h:34
bool has_error_stack(void)
const bool & get_logging(void)
void push_error_stack(void)
void deregister_thread_local(void)
void reserve_message_area(std::size_t size)
static context & get_thread_local_context(void)
const char * file_name
#define free_and_init(ptr)
Definition: memory_alloc.h:147
void set_error(int error_id, int error_severity, const char *filename, int line_no)
void clear_all_levels(void)
entry & get_entry(void)
const bool LOG_ME
#define ER_LAST_ERROR
Definition: error_code.h:1646
er_message(const bool &logging)
std::size_t msg_area_size