searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

MySQL Debug Package 源码分析

2024-11-08 09:21:30
7
0

MySQLDebug Package,涉及到源文件,主要是两个文件my_dbug.hdbug.cc

几个比较重要的结构:

Struct Settings
struct settings {
  uint flags;               /* Current settings flags               */
  uint maxdepth;            /* Current maximum trace depth          */
  uint delay;               /* Delay after each output line         */
  uint sub_level;           /* Sub this from code_state->level      */
  FILE *out_file;           /* Current output stream                */
  FILE *prof_file;          /* Current profiling stream             */
  char name[FN_REFLEN];     /* Name of output file                  */
  struct link *functions;   /* List of functions                    */
  struct link *p_functions; /* List of profiled functions           */
  struct link *keywords;    /* List of debug keywords               */
  struct link *processes;   /* List of process names                */
  struct settings *next;    /* Next settings in the list            */
};

用于记录配置项,其中前面介绍的flags以及flags后面紧跟的配置设置值,会被记录在该struct的实例中。

 Struct CODE_STATE
struct CODE_STATE {
  const char *process; /* Pointer to process name; usually argv[0] */
  const char *func;    /* Name of current user function            */
  int func_len;        /* How many bytes to print from func        */
  const char *file;    /* Name of current user file                */
  struct _db_stack_frame_ *framep; /* Pointer to current frame              */
  struct settings *stack; /* debugging settings                       */
  int lineno;             /* Current debugger output line number      */
  uint level;             /* Current function nesting level           */

  /*
   *      The following variables are used to hold the state information
   *      between the call to _db_pargs_() and _db_doprnt_(), during
   *      expansion of the DBUG_PRINT macro.  This is the only macro
   *      that currently uses these variables.
   *
   *      These variables are currently used only by _db_pargs_() and
   *      _db_doprnt_().
   */

  uint u_line;           /* User source code line number */
  int locked;            /* If locked with _db_lock_file_ */
  const char *u_keyword; /* Keyword for current macro */
  uint m_read_lock_count;
};

核心的数据结构,配置值,函数调用堆栈,调用信息的输出展示,均需要该结构。

struct _db_stack_frame_
struct _db_stack_frame_ {
  const char *func;   /* function name of the previous stack frame       */
  int func_len;       /* how much to print from func */
  const char *file;   /* filename of the function of previous frame      */
  unsigned int level; /* this nesting level, highest bit enables tracing */
  struct _db_stack_frame_ *prev; /* pointer to the previous frame */
};

函数调用栈的主要结构,记录了function名称,func_len,该函数所在的源文件,函数调用堆栈中的层级。

核心函数

code_state 函数
static CODE_STATE *code_state(void) {
  CODE_STATE *cs, **cs_ptr;
//如果全局init_settings没有初始化,对全局init_settings进行一次初始化
  if (!init_done) {
    init_done = true;
    native_mutex_init(&THR_LOCK_dbug, nullptr);
    native_mutex_init(&THR_LOCK_gcov, nullptr);
    native_rw_init(&THR_LOCK_init_settings);
    memset(&init_settings, 0, sizeof(init_settings));
    init_settings.out_file = stderr;
    init_settings.flags = OPEN_APPEND;
  }
//获取调用函数code_state的线程是否初始化了自己的code_sate对象。如果cs_ptr为空,说明是在该线程初始化之前调用了code_state。
  if (!(cs_ptr = my_thread_var_dbug()))
return nullptr; /* Thread not initialised */


//这一步,为该线程初始化一个code_state对象。
  if (!(cs = *cs_ptr)) {
    cs = (CODE_STATE *)DbugMalloc(sizeof(*cs));
    memset(cs, 0, sizeof(*cs));
    cs->process = db_process ? db_process : "dbug";
    cs->func = "?func";
    cs->file = "?file";
    cs->stack = &init_settings;
    cs->m_read_lock_count = 0;
    *cs_ptr = cs;
  }
// 将该线程的code_state对象的地址返回出去,后续返回的都将是本线程的code_state对象。
  return cs;
}
_db_enter_ 函数
//将当前_stack_frame_的信息赋值给code_state对象
void _db_enter_(const char *_func_, int func_len, const char *_file_,
                uint _line_, struct _db_stack_frame_ *_stack_frame_) {
  int save_errno;
  CODE_STATE *cs;
  if (!((cs = code_state()))) {
    _stack_frame_->level =
        0; /* Set to avoid valgrind warnings if dbug is enabled later */
    _stack_frame_->prev = nullptr;
    return;
  }
  save_errno = errno;

  read_lock_stack(cs);
//将code_state中的当前信息,保存在_stack_frame_中,
  _stack_frame_->func = cs->func;
  _stack_frame_->func_len = cs->func_len;
  _stack_frame_->file = cs->file;
//更新code_state当前信息
  cs->func = _func_;
  cs->func_len = func_len;
  cs->file = _file_;
//对_stack_frame_进行压栈处理
  _stack_frame_->prev = cs->framep;
  _stack_frame_->level = ++cs->level | framep_trace_flag(cs, cs->framep);
  cs->framep = _stack_frame_;
//判断trace设置状态
  switch (DoTrace(cs)) {
    case ENABLE_TRACE:
      cs->framep->level |= TRACE_ON;
      if (!TRACING) break;
      [[fallthrough]];
case DO_TRACE:
//如果trace中,则打印函数信息
      if (TRACING) {
        if (!cs->locked) native_mutex_lock(&THR_LOCK_dbug);
        DoPrefix(cs, _line_);
        Indent(cs, cs->level);
        (void)fprintf(cs->stack->out_file, ">%.*s\n", cs->func_len, cs->func);
	//刷新到trace输出文件。
        DbugFlush(cs); /* This does a unlock */
      }
      break;
    case DISABLE_TRACE:
      cs->framep->level &= ~TRACE_ON;
      [[fallthrough]];
    case DONT_TRACE:
      break;
  }
  errno = save_errno;

  unlock_stack(cs);
}
_db_return_函数
调用该函数,把 case_date stack_frame 堆栈当前头部的frame打印出出来,同时进行出栈出来,并销毁该stack_frame
void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_) {
  int save_errno = errno;
  uint _slevel_ = _stack_frame_->level & ~TRACE_ON;
  CODE_STATE *cs;
//宏定义,将本线程的code_state对象指针传给cs
  get_code_state_or_return;
//和_db_enter配对,在enter中压栈的stack_frame肯定和同函数中调用return 出栈的stack_frame相同,否则报错
  if (cs->framep != _stack_frame_) {
    char buf[512];
    snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
    DbugExit(buf);
  }

  read_lock_stack(cs);

  if (DoTrace(cs) & DO_TRACE) {
    if (TRACING) {
      if (!cs->locked) native_mutex_lock(&THR_LOCK_dbug);
     //根据debug设置,打印前缀信息
      DoPrefix(cs, _line_);
	//根据level信息,打印空格,level深的,其前面空格就多,方便观看函数调用层级
      Indent(cs, cs->level);
	//打印函数名,以及源文件行号
      if (_line_ == 0) {
        (void)fprintf(cs->stack->out_file, "<%.*s\n", cs->func_len, cs->func);
      } else {
        (void)fprintf(cs->stack->out_file, "<%.*s %u\n", cs->func_len, cs->func,
                      _line_);
      }
      DbugFlush(cs);
    }
  }
//将code_state 对象里的函数信息,level信息,file信息等修改为和传入的_stack_frame_相同。
//同时将cs_freamep堆栈移到下一层
  /*
    Check to not set level < 0. This can happen if DBUG was disabled when
    function was entered and enabled in function.
  */
  cs->level = _slevel_ != 0 ? _slevel_ - 1 : 0;
  cs->func = _stack_frame_->func;
  cs->func_len = _stack_frame_->func_len;
  cs->file = _stack_frame_->file;
  if (cs->framep != nullptr) cs->framep = cs->framep->prev;
  errno = save_errno;

  unlock_stack(cs);
}

 

0条评论
0 / 1000
c****q
1文章数
0粉丝数
c****q
1 文章 | 0 粉丝
c****q
1文章数
0粉丝数
c****q
1 文章 | 0 粉丝
原创

MySQL Debug Package 源码分析

2024-11-08 09:21:30
7
0

MySQLDebug Package,涉及到源文件,主要是两个文件my_dbug.hdbug.cc

几个比较重要的结构:

Struct Settings
struct settings {
  uint flags;               /* Current settings flags               */
  uint maxdepth;            /* Current maximum trace depth          */
  uint delay;               /* Delay after each output line         */
  uint sub_level;           /* Sub this from code_state->level      */
  FILE *out_file;           /* Current output stream                */
  FILE *prof_file;          /* Current profiling stream             */
  char name[FN_REFLEN];     /* Name of output file                  */
  struct link *functions;   /* List of functions                    */
  struct link *p_functions; /* List of profiled functions           */
  struct link *keywords;    /* List of debug keywords               */
  struct link *processes;   /* List of process names                */
  struct settings *next;    /* Next settings in the list            */
};

用于记录配置项,其中前面介绍的flags以及flags后面紧跟的配置设置值,会被记录在该struct的实例中。

 Struct CODE_STATE
struct CODE_STATE {
  const char *process; /* Pointer to process name; usually argv[0] */
  const char *func;    /* Name of current user function            */
  int func_len;        /* How many bytes to print from func        */
  const char *file;    /* Name of current user file                */
  struct _db_stack_frame_ *framep; /* Pointer to current frame              */
  struct settings *stack; /* debugging settings                       */
  int lineno;             /* Current debugger output line number      */
  uint level;             /* Current function nesting level           */

  /*
   *      The following variables are used to hold the state information
   *      between the call to _db_pargs_() and _db_doprnt_(), during
   *      expansion of the DBUG_PRINT macro.  This is the only macro
   *      that currently uses these variables.
   *
   *      These variables are currently used only by _db_pargs_() and
   *      _db_doprnt_().
   */

  uint u_line;           /* User source code line number */
  int locked;            /* If locked with _db_lock_file_ */
  const char *u_keyword; /* Keyword for current macro */
  uint m_read_lock_count;
};

核心的数据结构,配置值,函数调用堆栈,调用信息的输出展示,均需要该结构。

struct _db_stack_frame_
struct _db_stack_frame_ {
  const char *func;   /* function name of the previous stack frame       */
  int func_len;       /* how much to print from func */
  const char *file;   /* filename of the function of previous frame      */
  unsigned int level; /* this nesting level, highest bit enables tracing */
  struct _db_stack_frame_ *prev; /* pointer to the previous frame */
};

函数调用栈的主要结构,记录了function名称,func_len,该函数所在的源文件,函数调用堆栈中的层级。

核心函数

code_state 函数
static CODE_STATE *code_state(void) {
  CODE_STATE *cs, **cs_ptr;
//如果全局init_settings没有初始化,对全局init_settings进行一次初始化
  if (!init_done) {
    init_done = true;
    native_mutex_init(&THR_LOCK_dbug, nullptr);
    native_mutex_init(&THR_LOCK_gcov, nullptr);
    native_rw_init(&THR_LOCK_init_settings);
    memset(&init_settings, 0, sizeof(init_settings));
    init_settings.out_file = stderr;
    init_settings.flags = OPEN_APPEND;
  }
//获取调用函数code_state的线程是否初始化了自己的code_sate对象。如果cs_ptr为空,说明是在该线程初始化之前调用了code_state。
  if (!(cs_ptr = my_thread_var_dbug()))
return nullptr; /* Thread not initialised */


//这一步,为该线程初始化一个code_state对象。
  if (!(cs = *cs_ptr)) {
    cs = (CODE_STATE *)DbugMalloc(sizeof(*cs));
    memset(cs, 0, sizeof(*cs));
    cs->process = db_process ? db_process : "dbug";
    cs->func = "?func";
    cs->file = "?file";
    cs->stack = &init_settings;
    cs->m_read_lock_count = 0;
    *cs_ptr = cs;
  }
// 将该线程的code_state对象的地址返回出去,后续返回的都将是本线程的code_state对象。
  return cs;
}
_db_enter_ 函数
//将当前_stack_frame_的信息赋值给code_state对象
void _db_enter_(const char *_func_, int func_len, const char *_file_,
                uint _line_, struct _db_stack_frame_ *_stack_frame_) {
  int save_errno;
  CODE_STATE *cs;
  if (!((cs = code_state()))) {
    _stack_frame_->level =
        0; /* Set to avoid valgrind warnings if dbug is enabled later */
    _stack_frame_->prev = nullptr;
    return;
  }
  save_errno = errno;

  read_lock_stack(cs);
//将code_state中的当前信息,保存在_stack_frame_中,
  _stack_frame_->func = cs->func;
  _stack_frame_->func_len = cs->func_len;
  _stack_frame_->file = cs->file;
//更新code_state当前信息
  cs->func = _func_;
  cs->func_len = func_len;
  cs->file = _file_;
//对_stack_frame_进行压栈处理
  _stack_frame_->prev = cs->framep;
  _stack_frame_->level = ++cs->level | framep_trace_flag(cs, cs->framep);
  cs->framep = _stack_frame_;
//判断trace设置状态
  switch (DoTrace(cs)) {
    case ENABLE_TRACE:
      cs->framep->level |= TRACE_ON;
      if (!TRACING) break;
      [[fallthrough]];
case DO_TRACE:
//如果trace中,则打印函数信息
      if (TRACING) {
        if (!cs->locked) native_mutex_lock(&THR_LOCK_dbug);
        DoPrefix(cs, _line_);
        Indent(cs, cs->level);
        (void)fprintf(cs->stack->out_file, ">%.*s\n", cs->func_len, cs->func);
	//刷新到trace输出文件。
        DbugFlush(cs); /* This does a unlock */
      }
      break;
    case DISABLE_TRACE:
      cs->framep->level &= ~TRACE_ON;
      [[fallthrough]];
    case DONT_TRACE:
      break;
  }
  errno = save_errno;

  unlock_stack(cs);
}
_db_return_函数
调用该函数,把 case_date stack_frame 堆栈当前头部的frame打印出出来,同时进行出栈出来,并销毁该stack_frame
void _db_return_(uint _line_, struct _db_stack_frame_ *_stack_frame_) {
  int save_errno = errno;
  uint _slevel_ = _stack_frame_->level & ~TRACE_ON;
  CODE_STATE *cs;
//宏定义,将本线程的code_state对象指针传给cs
  get_code_state_or_return;
//和_db_enter配对,在enter中压栈的stack_frame肯定和同函数中调用return 出栈的stack_frame相同,否则报错
  if (cs->framep != _stack_frame_) {
    char buf[512];
    snprintf(buf, sizeof(buf), ERR_MISSING_RETURN, cs->func);
    DbugExit(buf);
  }

  read_lock_stack(cs);

  if (DoTrace(cs) & DO_TRACE) {
    if (TRACING) {
      if (!cs->locked) native_mutex_lock(&THR_LOCK_dbug);
     //根据debug设置,打印前缀信息
      DoPrefix(cs, _line_);
	//根据level信息,打印空格,level深的,其前面空格就多,方便观看函数调用层级
      Indent(cs, cs->level);
	//打印函数名,以及源文件行号
      if (_line_ == 0) {
        (void)fprintf(cs->stack->out_file, "<%.*s\n", cs->func_len, cs->func);
      } else {
        (void)fprintf(cs->stack->out_file, "<%.*s %u\n", cs->func_len, cs->func,
                      _line_);
      }
      DbugFlush(cs);
    }
  }
//将code_state 对象里的函数信息,level信息,file信息等修改为和传入的_stack_frame_相同。
//同时将cs_freamep堆栈移到下一层
  /*
    Check to not set level < 0. This can happen if DBUG was disabled when
    function was entered and enabled in function.
  */
  cs->level = _slevel_ != 0 ? _slevel_ - 1 : 0;
  cs->func = _stack_frame_->func;
  cs->func_len = _stack_frame_->func_len;
  cs->file = _stack_frame_->file;
  if (cs->framep != nullptr) cs->framep = cs->framep->prev;
  errno = save_errno;

  unlock_stack(cs);
}

 

文章来自个人专栏
技术成长
1 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0