作者:happytest
原文: http://happytest.blog.51cto.com/324097/62848
当你使用UPDATE, INSERT, DELETE语句更新数据的时候,你就改变了两个地方的数据:log buffer和data buffers。Buffers是固定长度的内存块,通常是512字节。
LOG BUFFER DATA BUFFER
================= ===============
= Log Record #1 = = Page Header =
= Log Record #2 = = Data Row =
= Log Record #3 = = Data Row =
= Log Record #4 = = Data Row =
================= ===============
例如:INSERT INTO JOBS VALUES(1,2,3)语句执行之后,log buffer将增加一个新的log记录,称为Log Record #5,它包含一个rowid和新记录的内容。同时,data buffer也将增加一个新行,但是,它会同时在页头标识:该页最新的log记录是Log Record #5。在这个例子中#5是Log Sequence Number(LSN),它对于接下来操作的时序安排是至关重要的。
================= ===============
= Log Record #1 = = Page Header =
= Log Record #2 = = Data Row =
= Log Record #3 = = Data Row =
= Log Record #4 = = Data Row =
================= ===============
例如:INSERT INTO JOBS VALUES(1,2,3)语句执行之后,log buffer将增加一个新的log记录,称为Log Record #5,它包含一个rowid和新记录的内容。同时,data buffer也将增加一个新行,但是,它会同时在页头标识:该页最新的log记录是Log Record #5。在这个例子中#5是Log Sequence Number(LSN),它对于接下来操作的时序安排是至关重要的。
下面是data-change的一些细节:
1.
一个INSERT log记录仅包含一个新数据,它对于在页上重做操作是足够的了,因此被称为一个redo条目。
2.
LSN不是log记录的一个域,它是文件中的一个绝对地址的相对偏移值。
在InnoDB改变了log buffer和data buffer之后,接下来就是写盘了。这就是复杂的地方。有多个线程在监控buffer的活动情况,有三种情况――overflow, checkpoint和commit――可以导致写盘操作。
Overflows情况下发生了什么?
Overflow是很少发生的情况,因为InnoDB采用pro-active措施来防止buffers被填满。但是我们还是来看看下面两种情况:
1.
如果log buffer满了,InnoDBInnoDB在buffer的末尾写log。那么情况向下面的图一样(log buffer只有四条记录的空间,现在插入第五条记录):
LOG FILE(S) BEFORE WRITING LOG RECORD #5
=================
= Log Record #1 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
LOG FILE(S) AFTER WRITING LOG RECORD #5
=================
= Log Record #5 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =|
=================
logs不可能永远增长。即使InnoDB使用了某些压缩算法,log文件还是会由于太大而不能放到任何磁盘驱动器上。因此InnoDB采取循环写的办法,也就是说将会覆盖前面就的log记录。
=================
= Log Record #1 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
LOG FILE(S) AFTER WRITING LOG RECORD #5
=================
= Log Record #5 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =|
=================
logs不可能永远增长。即使InnoDB使用了某些压缩算法,log文件还是会由于太大而不能放到任何磁盘驱动器上。因此InnoDB采取循环写的办法,也就是说将会覆盖前面就的log记录。
2.
如果data buffer满了,InnoDB将最近使用的buffer写入到数据库中,但是不可能足够的快。这种情况下,页头的LSN就起作用了。第一,InnoDB检查它的LSN是否比log文件中最近的log记录的LSN大,只有当log赶上了data的时候,才会将数据写到磁盘。换句话说,数据页不会写盘,直到相应的log记录需要写盘的时候。这就是先写日志策略。
CheckPoints的时候发生了什么?
前面说过InnoDB采取了一些pro-active措施来保证不发生overflows,其中最重要的措施就是checkpointing。有一个分离的线程,或者说从一组修改buffers的线程中分离出来的一个线程。在特定的时间间隔,checkpointer将醒来,检查buffer的改变,并保证写盘操作已经发生了。
大部分DBMS在这个时候,将会把所有的buffer写盘,这样可以保证所有改变了但是没写盘的buffer都写盘。就是说DBMS将通过”Sharp Checkpoint” flush所有”dirty”buffers。但是InnoDB只保证:(a)log和data buffers不会超过某个限制点;(b)log始终比data先写盘;(c)没有哪个data buffer的页头LSN等于被覆盖写的log记录。也就是说InnoDB是”Fuzzy Checkpoint”。
在COMMIT的时候,InnoDB不会将dirty data page写盘。之所以强调这个是因为,很容易让人想到,提交改变就是将所有东西写到一个持久媒介上。其实,只有log记录需要写。写dirty data page只可能发生在overflow或checkpoint时刻,因为它们的内容是多余的。
Recovery
在recovery里面可以看到log是非常必要的:当数据库发生异常的时候,数据是可以恢复的。
对于不是损坏磁盘驱动器的异常,恢复是自动进行的。InnoDB读取最新的checkpoint日志记录,检查dirty pages是否在异常发生前写到磁盘上了,如果没有,则读取影响该页的log记录并应用它们。这被称为”rolling forward”。因为有LSN,所以InnoDB只需要比较这个数字就可以进行同步。