WAL:Write after Logging 在数据之前写日志
虽然是先写数据到页缓冲区再写日志,但刷新到磁盘时要先刷新日志,再刷新数据。LSN是日志的最后一条的结束位置,只有日志都写好了才设置LSN。

插入数据分析:
数据结构: 页是最小的数据结构 一般是8K
基础认知 - 图1

image.png

Page Header:存储LSN:记录了该数据页最后被修改的日志序列位置,page中空闲空间的开始位置。LSN指的是某个页的LSN,即修改该页时,wal日志刷到磁盘的数目。数据页中的LSN与log中的LSN的区别

  1. ItemID: 数据指针数组存储指向实际数据的指针,数组中的元素ItemId可理解为相应数据行在Page中的实际开始偏移,数据行指针ItemID由三部分组成,前15位为Page内偏移,中间2位为标志,后面15位为长度
  2. 空闲空间:空闲空间为未使用可分配的空间,ItemID从空闲空间的头部开始分配,Item(数据行)从空闲空间的尾部开始
  3. 实际数据:实际数据为数据的行数据

特殊空间:用于存储索引访问使用的数据

  • log sequence number就是当前的redo log(in buffer)中的lsn;
  • log flushed up to是刷到redo log file on disk中的lsn;
  • pages flushed up to是已经刷到磁盘数据页上的LSN;
  • last checkpoint at是上一次检查点所在位置的LSN。

过程: 1,修改内存中的数据页,并在数据页中记录LSN,暂且称之为datain_buffer_lsn
2,修改数据页的同时,写入redolog buffer,并记录下对应的LSN,redolog_in
buffer_lsn
3, 触发了日志刷盘的规则时,会向磁盘刷入重做日志,并在该文件记录对应的LSN,redolog_in_disk
4, 某些情况下会触发checkPoint将内存脏页刷到磁盘,脏页刷盘结束时,在redolog记录checkpoint的LSN位置,暂且称之为checkpoint_lsn
5,刷数据页可能不是很快, 中途刷入的每个数据页都会记下当前页所在的lsn,每个数据页记录的实际上是自己所在的LSN,data_page_on_dis_lsn

redolog中的LSN记录刷到磁盘中的日志序号,而数据页中的LSN,数据与日志相对应,刷到磁盘数据页也会记录现在刷入的LSN

见其他的wiki 更详细的情况 或者论坛

Items(Tuples):第一部分是Tuple头部信息,第二部分是实际的数据。

头部数据包括:

  1. - xmin 创建的事务id
  2. - xmax 最新的事务id
  3. - vacuum == purge

在pg中,由于MVCC需要,UPDATE或DELETE某行时不会立即删除该行的旧版本。但是当被删除的行版本已不再被任何事务需要时,必须回收它占用的空间以供新行重用,避免磁盘空间无限制地增长。标准VACUUM可清理表和索引中的死元组,并将其标记为可重用空间。但是,它不会将空间返回给操作系统

插入数据:
buffer: 是一个标记,是一个数,表示位置
本地buffer用于临时表的读写,共享buffer用于多线程并发。
initBufferPool:初始化缓冲区描述器,以及分配空间
bufferAlloc:分配缓冲区,是否有所,以及是否是脏块,并且需要判断引用计数是否为0.

从heap_insert开始:
补充:结构体指针就相当于引用,想传值还是传引用,这就是选择 fun(* p) 形参是p,而调用的时候
使用fun(&p),也就是传递了地址过去,指针就是地址,然后就相当于传递引用了

进程的启动

一般通过fork+exec系列函数来实现,前者将当前进程“分叉”出一个孪生子进程,后者负责替换这个子进程的执行文件,来执行子进程的新程序文件。创建进程时,创建内核中用于描述进程的数据结构,创建新进程的页目录、页表,用于构建新进程的内存地址空间,通过fork成功创建进程后,此时的子进程和父进程相当于一个细胞进行了有丝分裂,两个进程“几乎”是一模一样的。而要想子进程执行新的程序,在子进程中还需要用到exec系列函数来实现对进程可执行程序的替换。无论是ELF文件还是PE文件,在各自的文件头中,都记录了这个可执行文件的指令入口地址,它指示了程序该从哪里开始执行。在_start的结尾,调用了__libc_start_main函数,而这个函数,位于libc.so中。

概念再次深入:

而 InnoDB 是另一个公司以插件形式引入 MySQL 的,既然只依靠 binlog 是没有 crash-safe 能力的,所以 InnoDB 使用另外一套日志系统——也就是 redo log 来实现 crash-safe 能力。

如何恢复数据:
pg:time_line
mysql: 找到一次全量备份,+ binlog执行即可恢复
因此要么没有恢复数据这个功能,要么需要自己在mysql当中实现time_line,显然这个机制的实现还是比较复杂,并且还需要实现恢复功能。pg中的wal日志是长期保存的,而mysql当中是循环覆盖