2. log buffer的内部管理机制
日志缓冲区的内部管理分为两部分,一部分是重做记录的生成,另一部分就是重做记录写入联机日志
文件。这两部分不是孤立的,没有关联的。在生成重做记录的过程中,可能会触发LGWR将重做记录写入联机日志文件。
我们先用一个实例来说明在日志缓冲区中的操作过程,并使用[file# , blk#]来表示某个数据块,file#表示文件号,blk#表示数据块号。
假设session 1发出更新语句:update redo_test set name='cdf' where id=1;
Oracle首先找出id=1所在的数据块(假设为[file#4,blk#120])放入buffer cache,然后找出一个可用的回滚段数据块(假设为[file#2,blk#19]),将旧值'abc'放入该块,同时生成重做记录。然后将'cdf'放入表的数据块,再生成重做记录。这时的日志缓冲区的结构类似如下。(我们从前面描述日志缓冲区的内存结构时,知道重做记录中最重要的就下面列的这几列内容。同时,下面的一行就表示一个改动向量):
行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
这时假设session 2发出其他更新语句:update t set c1=10 where c1=9;
同样的道理,oracle找到该数据块(假设为[file#5,blk#200])放入buffer cache,并找到回滚段数据块(假设为[file#2,blk#30])存放旧值,生成重做记录,更新表的数据块,再次生成重做记录。这时的日志缓冲区的结构类似如下:
行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
4 T20 5 200 20 1 10
这时,session 1又发出更新语句:update redo_test set name='xyz1' where id=2,并提交(commit)。
同样的方式处理回滚段和数据块,并生成重做记录。假设这时生成日志缓冲区假设为:
行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
4 T20 5 200 20 1 10
5 T1 2 19 - - abc
6 T1 4 120 2 2 xyz1
7 T1 commit SCN timestamp
这时,我们可以注意到,提交标记也被记录到了重做记录中。从我们前面转储出的结果中也可以看到“sta: 9”的内容,这就是提交标记。每次提交时,都会生成一个SCN号,SCN号越小,说明发生的越早,其所属的重做记录就越排在前面。一旦用户发出commit语句,系统就会触发LGWR进程。这时,LGWR进程会将上面所显示的所有重做记录都写入联机日志文件中。注意,其中也包括尚未提交的事务T20。
在LGWR写这些重做记录的过程中,又有其他session 发出更新语句,并提交。这时的日志缓冲区假设如下所示:
行号 事务id file# block# row column value
1 T1 2 19 - - abc
2 T1 4 120 1 2 cdf
3 T20 2 30 - - 9
4 T20 5 200 20 1 10
5 T1 2 19 - - abc
6 T1 4 120 2 2 xyz1
7 T1 commit SCN timestamp 以上的重做日志正在由LGWR写入
------------------------------------------------------------------------------------------
8 T20 2 39 - - 289 在LGWR写时生成以下的重做日志
9 T20 5 498 220 3 190
10 T9 2 90 - - hhh
11 T9 9 100 20 9 xxx
12 T9 commit SCN timestamp
13 T18 2 189 - - 18
14 T18 10 29 300 10 20
15 T18 commit SCN timestamp
当LGWR写完第一批重做记录(第1到第7行)以后,就会立即开始写第二批重做记录(第8行到第15行)。注意,第二批重做记录中,存在两个commit,但LGWR不会分成两次来写,而是一次就将它们全部写入。当LGWR在写完第1到第7行的改动向量以后,这部分的日志缓冲区内存就被释放了,可以被新生成的重做记录所覆盖。

