02 mysql调试的一些基础方法

前言

呵呵 也是最近才开始接触了调试 mysql, 但是 调试起来还是有一些 迷糊的地方 

因此 今天整理了一些 基础的调试方式方法吧,  定位查询到记录的数据信息, 数据记录的存放方式, mysql 服务器回传数据给客户端的一些地方  

也找了一下 MySQL多版本并发控制机制(MVCC)-源码浅析 的作者请教了一下 

接上一篇文章 01 mysql可重复读的几种情况的调试, 这下就可以确定对应的当前版本, 前一个版本的记录的信息了 

 

 

相关代码, 调试信息来自

master:~ jerry$ cat /System/Library/CoreServices/SystemVersion.plist




	ProductBuildVersion
	18E2035
	ProductCopyright
	1983-2019 Apple Inc.
	ProductName
	Mac OS X
	ProductUserVisibleVersion
	10.14.4
	ProductVersion
	10.14.4
	iOSSupportVersion
	12.2


 
mysql> select version();
+--------------+
| version()    |
+--------------+
| 5.6.33-debug |
+--------------+
1 row in set (0.00 sec)

 

 

测试表

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `age` int(11) DEFAULT 0,
  `name` varchar(64),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 ;

基础测试数据

-- 重新构造测试数据
delete from user;
insert into user values ('1', '27', 'jerry');

 

 

1. 计算字段偏移的地方

02 mysql调试的一些基础方法_第1张图片

其中一处地方在 这里, 从这里计算的偏移结果如下  

计算偏移的函数 offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &heap);
offsets 的存储数据如下
offsets[0] = n_alloc;
offsets[1] = n_fields;
offsets[2] = (ulint) rec;
offsets[3] = (ulint) index;
offsets[4] = (rec - (lens + 1)) | REC_OFFS_COMPACT | any_ext;
offsets[5] = 4
offsets[6] = 10
offsets[7] = 17
offsets[8] = 21
offsets[9] = 26



# 一个 offsets 的内存结构大致如下, 添加于 2021.03.25 
(lldb) x 0x7000077841c0 -c 0x64 
0x7000077841c0: 64 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00  d...............
0x7000077841d0: 7f 40 6a 2a 01 00 00 00 58 3f 48 ed d0 7f 00 00  .@j*....X?H��...
0x7000077841e0: 07 00 00 80 00 00 00 00 04 00 00 00 00 00 00 00  ................
0x7000077841f0: 0a 00 00 00 00 00 00 00 11 00 00 00 00 00 00 00  ................
0x700007784200: 15 00 00 00 00 00 00 00 1a 00 00 00 00 00 00 00  ................
0x700007784210: 00 00 00 00 00 00 00 00 1e b2 8a 0d 00 00 01 00  .........�......
0x700007784220: 60 42 78 07                                      `Bx.

rec 为当前记录的信息, index 为当前记录的 cluster index, offsets 为偏移量接收结果 

offsets[0] 表示 offsets 的长度

offsets[1] 表示 字段的数量 

offsets[2] 表示 rec 的地址

offsets[3] 表示 index 的地址

offsets[4] rec 的附加信息的长度 ?

offsets[5-9] 表示字段 1, 2, 3, 4, 5 的结束的偏移, 偏移结束相减得到对应的字段的占用的长度

 

 

2. 查看一下 rec 的数据信息

# remOrec.cc, 描述了 rec 的存储结构
| length of the last non-null variable-length field of data:
  if the maximum length is 255, one byte; otherwise,
  0xxxxxxx (one byte, length=0..127), or 1exxxxxxxxxxxxxx (two bytes,
  length=128..16383, extern storage flag) |
...
| length of first variable-length field of data |
| SQL-null flags (1 bit per nullable field), padded to full bytes |
| 4 bits used to delete mark a record, and mark a predefined
  minimum record in alphabetical order |
| 4 bits giving the number of records owned by this record
  (this term is explained in page0page.h) |
| 13 bits giving the order number of this record in the
  heap of the index page |
| 3 bits record type: 000=conventional, 001=node pointer (inside B-tree),
  010=infimum, 011=supremum, 1xx=reserved |
| two bytes giving a relative pointer to the next record in the page |
ORIGIN of the record
| first field of data |
...
| last field of data |

rec 记录的相关信息如下, rec 之前还有 一部分字节的额外的信息  

 

## rec 的业务数据
(lldb) x (0x11d52807f)
0x11d52807f: 80 00 00 01 00 00 00 00 21 0e 88 00 00 01 3e 01  ........!.....>.
0x11d52808f: 10 80 00 00 1b 6a 65 72 72 79 00 00 00 00 00 00  .....jerry......

rec = 0x 80
id = 0x 80 00 00 01
trx_id = 0x 00 00 00 00 21 0e = 8462
poll_ptr = 0x 88 00 00 01 3e 01 10
age = 0x 80 00 00 1b = 27
name = 6a 65 72 72 79 = jerry

 

## 业务数据之前的部分
(lldb) x 0x11d528078
0x11d528078: 05 00 00 00 10 ff f1 80 00 00 01 00 00 00 00 21  ...............!

0x11d528078 : 05 = lengthOf('jerry')
0x11d528079 : 00 = nulls
0x11d52807a : 0 = delete flag : at 0x20UL & first user record on a non-leaf B-tree page that is the leftmost page : 0x10UL
0x11d52807a : 0 = number of records owned by this record
0x11d52807b : 00 = order number of this record in the heap of the index page(0b 0000 0000 0001 0 = 2)
0x11d52807c : 10 = nuorder number of this record in the heap of the index page & record type(0b 000 = conventional)
0x11d52807d : ff f1 = relative pointer to the next record in the page

 

mvvc, 判断记录是否被标记删除的方式
rec_get_deleted_flag

02 mysql调试的一些基础方法_第2张图片

 

 

3. 将结果数据从 rec 里面查询写到 *buf  暂存

## 将数据写出到 *buf(对应于后面的每一个 field.ptr, 所以后面从 field(item) 到 packet 传递数据是直接读取的 field.ptr 的数据)(而 buf 和 field.ptr 的关系居然在创建 consistent view 之前就关联好了?, 试问怎么计算的偏移.., 牛逼)
row_sel_store_mysql_rec 将数从 rec 中写出 *buf
(lldb) x 0x7f917a0bea50
0x7f917a0bea50: fc 01 00 00 00 1b 00 00 00 05 6a 65 72 72 79 00  ..........jerry.

0x7f917a0bea50 : fc = 标记 ?
0x7f917a0bea51 : 01 = id
0x7f917a0bea52 : 00 00 00 1b = age
0x7f917a0bea56 : 00 00 00 05 = lengthOf('jerry')
0x7f917a0bea5a : 6a 65 72 72 79 = jerry

 

 

4. 服务器封装返回结果信息 

## 返回结果相关
详解MySQL Server端如何发送结果集给客户端
https://blog.csdn.net/maray/article/details/49932147

Protocol::send_result_set_row : 将查询结果返回回去, 返回给客户端, 这里是在封包
net_store_length : 存储相关返回结果的长度, 可以在这里打上一个断点

# 当前 protocol 信息如下, packet_length 为 11
this = {Protocol_text * | 0x7f917803a908} 0x00007f917803a908
 Protocol = {Protocol}
  thd = {THD * | 0x7f917803a400} 0x00007f917803a400
  packet = {String * | 0x7f917803a9d8} 0x00007f917803a9d8
   Ptr = {char * | 0x7f917b01f000} "\x011\x0227\x05jerryser\x04user\x04name\x04name\f!"
   str_length = {uint32} 11
   Alloced_length = {uint32} 16384
   alloced = {bool} true
   str_charset = {const CHARSET_INFO * | 0x10213b8c8} 0x000000010213b8c8
  convert = {String * | 0x7f917803a9f8} 0x00007f917803a9f8
  field_pos = {uint} 3
  field_types = {enum_field_types * | 0x7f917987f950} 0x00007f917987f950
  field_count = {uint} 3

(lldb) x 0x7f917b01f000
0x7f917b01f000: 01 31 02 32 37 05 6a 65 72 72 79 73 65 72 04 75  .1.27.jerryser.u
0x7f917b01f000 : 01 表示 id 占用 1 byte
0x7f917b01f001 : 31 表示 id 值为 1
0x7f917b01f002 : 02 表示 age 占用 2 byte
0x7f917b01f003 : 32 37 表示 age 值为 27
0x7f917b01f005 : 05 表示 name 占用 5 byte
0x7f917b01f006 : 6a 65 72 72 79 表示 name 值为 jerry

 

 

 

 

参考

详解MySQL Server端如何发送结果集给客户端

 

 

你可能感兴趣的:(12,mysql,mysql,debug)