mysql8.0源码解析 InnoDB redo log日志 写 write ahead 巧用pageCache实现高效写
作者:互联网
pageCache背景
当往磁盘上写文件时,如果文件内容还没有被缓存或者被置换出去了,在内存里不存在对应的page cache,则需要先将对应page的内容从磁盘上读到内存里,修改要写入的数据,然后再将整个page写回到磁盘;在这种情况下,会有一次额外的读IO开销,IO的性能会有一定的损失。
mysql的整体性能高度依赖redo log写IO的性能,InnoDB对对redo日志的写做了优化,redo log写入是追加写的模式(append write),引入了write ahead方法。巧用一个8192字节大小的内存空间(log.write_ahead_buf),实现pageCahe的高效写入。
write ahead 基本原理
利用8192字节大小的内存与ib_logfile 的pageCache 对齐,一次性生成pageCache,而不会出现先读后写的情况。
当第一次写的时候,先生成8192字节大小的缓存。
redo日志大小不同情况的说明
1 小于512字节
2 连续几次之和小于512字节
3 大于512字节,如600字节
4 大于8192字节 ,因引入write ahead,一次写入最大值为8192
5 小于8192字节
write ahead剩余空间大小不同情况的说明
1 剩余为0 ,即开启新一轮的cache
2 剩余空间 不足一次写入redo日志大小
3 剩余空间满足一次写入
对不同情况的画图描述
剩余为0 写入大于8192
先从 write_ahead_buf 的log.write_ahead_end_offset 与 log.current_file_real_offset 相等开始,
有8192字节 redo日志需要写入,因size >= 8192 直接写入pageCache,write_ahead_buf的log.write_ahead_end_offset 不变,下一轮操作再更新
这时 write_ahead_buf 的log.write_ahead_end_offset 比 log.current_file_real_offset小8192,需要补齐
保证log.write_ahead_end_offset 与 log.current_file_real_offset 对齐
上次剩余为0,连续两次512字节或者
此时write_ahead_buf 的log.write_ahead_end_offset 与 log.current_file_real_offset 相等
现在写入一个512字节的redo日志(大于512小于1024,则只写入512字节,下面代码中详解)
现在write_ahead_buf 的空间为0(不是write_ahead_buf8192的字节大小,而是逻辑上虚拟空间)
需要增加逻辑空间为8192,把buffer中的512字节复制到write_ahead_buf 中,第一次要写8192字节
写入pageCahe,形成一个8192字节大小的缓存区
再次写入一个512字节,直接把512字节写入的pageCache,绕开write_ahead_buf.如上图
连续几次写入的大小之和小于512
当write_ahead_buf 中还有虚拟空间时,写入小于512字节(假如写入25字节)
需要把redo日志复制到write_ahead_buf中,剩余空间补0,修改12字节的block头和4字节的block尾,因不足512字节,需要修改12字节的表头,不能在bufferCache中直接修改,会冲突(buffer Cache是并发写,没有锁),这也是巧用write_ahead_buf 的好处
把512字节的大小写入pageCache中
再次写入45字节(两次之和小于512),需要从上次的起始位置即需要复制25+45个字节复制到write_ahead_buf中,
剩余空间补0,修改12字节的block头和4字节的block尾,再把此512字节复制到pageCache中,覆盖上一次的pageCache中的512字节
代码详解-log_files_write_buffer
注源码为mysql8.0.20
log0write.cc
/*此函主要是把buffer的redo日志,通过write_ahead 功能,把redo日志写入ib_logfile的缓存(pageCache)*/
1624 static void log_files_write_buffer(log_t &log, byte *buffer, size_t buffer_size,
1625 lsn_t start_lsn) {
1626 ut_ad(log_writer_mutex_own(log));
1627
1628 using namespace Log_files_write_impl;
1629
1630 validate_buffer(log, buffer, buffer_size);
1631
1632 validate_start_lsn(log, start_lsn, buffer_size);
1633
1634 checkpoint_no_t checkpoint_no = log.next_checkpoint_no.load();
1635 /*得到当前start_lsn在文件中的偏移,ib_logfile是循环使用,start_lsn 可能是ib_logfile总大小的几倍,start_lsn的大小转换成文件的偏移*/
1636 const auto real_offset = compute_real_offset(log, start_lsn);
1637
1638 bool write_from_log_buffer;
1639 /*计算本次要写入redo日志的大小
当大于8192时,则截断为8192,一次最大写入8192
根据情况判断,判断是否需要把redo日志复制到write_ahead_buf,确定其write_from_log_buffer状态,为true 则不需要复制,为false ,需要把buffer中的redo复制到write_from_log_buffer
*/
1640 auto write_size = compute_how_much_to_write(log, real_offset, buffer_size,
1641 write_from_log_buffer);
1642 /*
start_next_file 函数解析
当上次写的文件尾时,本次返回为0,则做文件切换
主要更新log.current_file_lsn log.current_file_real_offset log.current_file_end_offset 这三个变量(这三个变量),实现文件的切换
这三个变量仅在启动时 和切换文件时修改
log.current_file_lsn 随着 lsn的增长而增长
log.current_file_real_offset 是整个文件总和的偏移量,>=2048 且 < 全部ib_logfile文件的总大小
log.current_file_end_offset 当前要写的ib_logfile 文件的结尾
*/
1643 if (write_size == 0) {
1644 start_next_file(log, start_lsn);
1645 return;
1646 }
1647 /*如果write_size大与512,则填充block的12字节的头和4字节的校验尾
只填充512的block,如果不足512的部分,不在此函数的处理范围中
*/
1648 prepare_full_blocks(log, buffer, write_size, start_lsn, checkpoint_no);
1649
1650 byte *write_buf;
1651 uint64_t written_ahead = 0;
1652 lsn_t lsn_advance = write_size;
1653
1654 if (write_from_log_buffer) {
1655 /* We have at least one completed log block to write.
1656 We write completed blocks from the log buffer. Note,
1657 that possibly we do not write all completed blocks,
1658 because of write-ahead strategy (described earlier). */
1659 DBUG_PRINT("ib_log",
1660 ("write from log buffer start_lsn=" LSN_PF " write_lsn=" LSN_PF
1661 " -> " LSN_PF,
1662 start_lsn, log.write_lsn.load(), start_lsn + lsn_advance));
1663 /*利用write_buf指针,指向buffer缓存*/
1664 write_buf = buffer;
1665
1666 LOG_SYNC_POINT("log_writer_before_write_from_log_buffer");
1667
1668 } else {
1669 DBUG_PRINT("ib_log",
1670 ("incomplete write start_lsn=" LSN_PF " write_lsn=" LSN_PF
1671 " -> " LSN_PF,
1672 start_lsn, log.write_lsn.load(), start_lsn + lsn_advance));
1673
1674 #ifdef UNIV_DEBUG
1675 if (start_lsn == log.write_lsn.load()) {
1676 LOG_SYNC_POINT("log_writer_before_write_new_incomplete_block");
1677 }
1678 /* Else: we are doing yet another incomplete block write within the
1679 same block as the one in which we did the previous write. */
1680 #endif /* UNIV_DEBUG */
1681 /*write_from_log_buffer 为false
利用write_buf指针,指向write_ahead缓存*/
1682 write_buf = log.write_ahead_buf;
1683
1684 /* We write all the data directly from the write-ahead buffer,
1685 where we first need to copy the data. */
/*write_size大小的redo从buffer中复制到log.write_ahead_buf
把log.write_ahead_buf中最后一个不足512的block 补0
并把write_size大小512向下对齐,如果不能被512整除,则把最后一个block补0的长度加到write_size,使其能够与512整除
*/
1686 copy_to_write_ahead_buffer(log, buffer, write_size, start_lsn,
1687 checkpoint_no);
1688 /*判断write_ahead的虚拟空间是否完全被占用,用1个字节来判断,如果1字节个都放不下则虚拟空间用尽*/
1689 if (!current_write_ahead_enough(log, real_offset, 1)) {
/*write_ahead 虚拟空间用尽时,需要判断ib_logfile 当前文件的剩余空间(当前偏移到文件尾的偏移)是否足够放下当前要写的redo日志的大小
返回值为write_ahead 虚拟空间剩余空间
*/
1690 written_ahead = prepare_for_write_ahead(log, real_offset, write_size);
1691 }
1692 }
1693
1694 srv_stats.os_log_pending_writes.inc();
1695
1696 /* Now, we know, that we are going to write completed
1697 blocks only (originally or copied and completed). */
/*把write_size的小的redo日志写入ib_logfile的缓存(pageCache)*/
1698 write_blocks(log, write_buf, write_size, real_offset);
1699
1700 LOG_SYNC_POINT("log_writer_before_lsn_update");
1701
1702 const lsn_t old_write_lsn = log.write_lsn.load();
1703 /*lsn_advance 不是写入pageCache的大小,补0的部分不包含在此变量中,lsn_advance 为当前写入redo日志的大小
当对于连续几次小范围的redo日志写入时,lsn_advance为几次写的总和
start_lsn 为512对齐,并不是上次结束的位置
start_lsn <= old_write_lsn
*/
1704 const lsn_t new_write_lsn = start_lsn + lsn_advance;
1705 ut_a(new_write_lsn > log.write_lsn.load());
1706 /*更新log.write_lsn为当前最新的值*/
1707 log.write_lsn.store(new_write_lsn);
1708 /*通知Log write_notifier thread*/
1709 notify_about_advanced_write_lsn(log, old_write_lsn, new_write_lsn);
1710
1711 LOG_SYNC_POINT("log_writer_before_buf_limit_update");
1712
1713 log_update_buf_limit(log, new_write_lsn);
1714
1715 srv_stats.os_log_pending_writes.dec();
1716 srv_stats.log_writes.inc();
1717
1718 /* Write ahead is included in write_size. */
1719 ut_a(write_size >= written_ahead);
1720 srv_stats.os_log_written.add(write_size - written_ahead);
1721 MONITOR_INC_VALUE(MONITOR_LOG_PADDED, written_ahead);
1722
1723 int64_t free_space = log.lsn_capacity_for_writer - log.extra_margin;
1724
1725 /* The free space may be negative (up to -log.extra_margin), in which
1726 case we are in the emergency mode, eating the extra margin and asking
1727 to increase concurrency_margin. */
1728 free_space -= new_write_lsn - log.last_checkpoint_lsn.load();
1729
1730 MONITOR_SET(MONITOR_LOG_FREE_SPACE, free_space);
1731
1732 log.n_log_ios++;
1733 /*判断是否更新 log.write_ahead_end_offset
本地虚拟空间用尽时不更新此变量
当本地虚拟空间用尽后,第一次写入时,更新log.write_ahead_end_offset,即增加8192
*/
1734 update_current_write_ahead(log, real_offset, write_size);
1735 }
代码详解-compute_how_much_to_write
简单介绍下compute_real_offset此函,虽然短小,但很经典,主要计算出当前lsn在整个文件的绝对偏移量(real_offset),lsn 映射成应写在ib_logfile文件中的位置。
为写入
为写入redo日志的大小,但是start_lsn - log.current_file_lsn 不等于图示的大小,而是一个相对大小
log0write.cc
1223 static inline uint64_t compute_real_offset(const log_t &log, lsn_t start_lsn) {
/*start_lsn 当前开始写的lsn的起始值
log.current_file_lsn 在启动或切换文件后确定,相对于lsn的一个固定位置
log.current_file_real_offset 在启动或切换文件后确定 ,相对于文件大小的偏移量
*/
1228 const auto real_offset =
1229 log.current_file_real_offset + (start_lsn - log.current_file_lsn);
1230
1239
1240 return (real_offset);
1241 }
compute_how_much_to_write 函数
log0write.cc
/*
计算本次可以写redo日志的大小
real_offset 在文件的绝对偏移量
buffer_size 需要写入redo日志的大小
write_from_log_buffer 返回参数
true buffer中的redo日志不需要复制到write_ahead_buf中
false buffer中的redo日志需要复制到write_ahead_buf中
*/
1310 static inline size_t compute_how_much_to_write(const log_t &log,
1311 uint64_t real_offset,
1312 size_t buffer_size,
1313 bool &write_from_log_buffer) {
1314 size_t write_size;
1315
1316 /* First we ensure, that we will write within single log file.
1317 If we had more to write and cannot fit the current log file,
1318 we first write what fits, then stops and returns to the main
1319 loop of the log writer thread. Then, the log writer will update
1320 maximum lsn up to which, it has data ready in the log buffer,
1321 and request next write operation according to its strategy. */
/*当前的文件的偏移量(real_offset)到文件尾的空间大小是否满足 buffer_size的大小*/
1322 if (!current_file_has_space(log, real_offset, buffer_size)) {
1323 /* The end of write would not fit the current log file. */
1324
1325 /* But the beginning is guaranteed to fit or to be placed
1326 at the first byte of the next file. */
1327 ut_a(current_file_has_space(log, real_offset, 0));
1328 /*当前的文件的偏移量(real_offset)到文件尾的空间大小是否0 判断上次是否已经把空间全部写满,如果写满则返回0 准备切换文件*/
1329 if (!current_file_has_space(log, real_offset, 1)) {
1330 /* The beginning of write is at the first byte
1331 of the next log file. Flush header of the next
1332 log file, advance current log file to the next,
1333 stop and return to the main loop of log writer. */
1334 write_from_log_buffer = false;
1335 return (0);
1336
1337 } else {
1338 /* We write across at least two consecutive log files.
1339 Limit current write to the first one and then retry for
1340 next_file. */
1341
1342 /* If the condition for real_offset + buffer_size holds,
1343 then the expression below is < buffer_size, which is
1344 size_t, so the typecast is ok. */
/*buffer_size大于当前的剩余空间,则只能写剩余空间的大小,下次则走一个分支,切换文件
write_size 为剩余空间的大小
*/
1345 write_size =
1346 static_cast<size_t>(log.current_file_end_offset - real_offset);
1347
1348 ut_a(write_size <= buffer_size);
1349 ut_a(write_size % OS_FILE_LOG_BLOCK_SIZE == 0);
1350 }
1351
1352 } else {
/*如果空间足够大,则直接赋值*/
1353 write_size = buffer_size;
1354
1355 ut_a(write_size % OS_FILE_LOG_BLOCK_SIZE >= LOG_BLOCK_HDR_SIZE ||
1356 write_size % OS_FILE_LOG_BLOCK_SIZE == 0);
1357
1358 ut_a(write_size % OS_FILE_LOG_BLOCK_SIZE <
1359 OS_FILE_LOG_BLOCK_SIZE - LOG_BLOCK_TRL_SIZE);
1360 }
1361
1362 /* Now, we know we can write write_size bytes from the buffer,
1363 and we will do the write within single log file - current one. */
1364
1365 ut_a(write_size > 0);
1366 ut_a(real_offset >= log.current_file_real_offset);
1367 ut_a(real_offset + write_size <= log.current_file_end_offset);
1368 ut_a(log.current_file_real_offset / log.file_size + 1 ==
1369 log.current_file_end_offset / log.file_size);
1370
1371 /* We are interested in writing from log buffer only,
1372 if we had at least one completed block for write.
1373 Still we might decide not to write from the log buffer,
1374 because write-ahead is needed. In such case we could write
1375 together with the last incomplete block after copying. */
1376 write_from_log_buffer = write_size >= OS_FILE_LOG_BLOCK_SIZE;
1377
1378 if (write_from_log_buffer) {
1379 MONITOR_INC(MONITOR_LOG_FULL_BLOCK_WRITES);
1380 } else {
1381 MONITOR_INC(MONITOR_LOG_PARTIAL_BLOCK_WRITES);
1382 }
1383
1384 /* Check how much we have written ahead to avoid read-on-write. */
1385 /*当前的文件的偏移量(real_offset)到write_ahead尾的空间大小是否满足buffer_size的大小*/
1386 if (!current_write_ahead_enough(log, real_offset, write_size)) {
/*当前的文件的偏移量(real_offset)到write_ahead尾的空间大小是否0 判断上次是否已经把空间全部写满,如果写满 则下次更新 write_ahead_end_offset*/
1387 if (!current_write_ahead_enough(log, real_offset, 1)) {
1388 /* Current write-ahead region has no space at all. */
1389 /*说明上次写已经到write_ahead尾,则根据real_offset起始,计算一个8192空间大小的write_ahead尾值next_wa*/
1390 const auto next_wa = compute_next_write_ahead_end(real_offset);
1391 /*判断新计算的write_ahead尾值 满足 write_size的大小*/
1392 if (!write_ahead_enough(next_wa, real_offset, write_size)) {
1393 /* ... and also the next write-ahead is too small.
1394 Therefore we have more data to write than size of
1395 the write-ahead. We write from the log buffer,
1396 skipping last fragment for which the write ahead
1397 is required. */
1398
1399 ut_a(write_from_log_buffer);
1400 /*上一次用尽,新计算的尾值也不能满足,则write_size 已经大于write-ahead的总量,一般大于8192,如果写入的大小大于8192 ,则只能写8192,且不需要要把buffer中的redo日志复制到write-ahead,而是直接写到pageCache
*/
1401 write_size = next_wa - real_offset;
1402
1403 ut_a((real_offset + write_size) % srv_log_write_ahead_size == 0);
1404
1405 ut_a(write_size % OS_FILE_LOG_BLOCK_SIZE == 0);
1406
1407 } else {
1408 /* We copy data to write_ahead buffer,
1409 and write from there doing write-ahead
1410 of the bigger region in the same time. */
/*
当write-ahead上次用尽后,则需要新开辟一个8192的pageCache,
当第一写不满足8192时,则把当前要写入的redo日志复制到write-ahead,剩余空间补0,
8192个字节一次写入redo日志,形成一个8192大小的pageCache
此处为整个pageCache利用的精华,有画龙点睛的意思
*/
1411 write_from_log_buffer = false;
1412 }
1413
1414 } else {
1415 /* We limit write up to the end of region
1416 we have written ahead already. */
/*pageCache 剩余空间不足要写入write_size的大小,则重新计算write_head大小此次把pageCache用尽,下次则开辟一个块新的空间*/
1417 write_size =
1418 static_cast<size_t>(log.write_ahead_end_offset - real_offset);
1419
1420 ut_a(write_size >= OS_FILE_LOG_BLOCK_SIZE);
1421 ut_a(write_size % OS_FILE_LOG_BLOCK_SIZE == 0);
1422 }
1423
1424 } else {
1425 if (write_from_log_buffer) {
/*此处完全执行需要满足几个条件
1 PageCache的空间足够大
2 不是第一次写
3 大于等于512
执行的结果为512的整数倍,不足512的丢弃,并得到实际写入大小
*/
1426 write_size = ut_uint64_align_down(write_size, OS_FILE_LOG_BLOCK_SIZE);
1427 }
1428 }
1429 /*通过复杂的计算,返回写pageCache大小*/
1430 return (write_size);
1431 }
代码详解 copy_to_write_ahead_buffer
/*
此函数实现两个功能
把buffer中的redo日志复制到write-ahead 中
把不足512字节的redo日志补0 ,并计算填充block的头和尾
*/
1518 static inline void copy_to_write_ahead_buffer(log_t &log, const byte *buffer,
1519 size_t &size, lsn_t start_lsn,
1520 checkpoint_no_t checkpoint_no) {
1521 ut_a(size <= srv_log_write_ahead_size);
1522
1523 ut_a(buffer >= log.buf);
1524 ut_a(buffer + size <= log.buf + log.buf_size);
1525
1526 byte *write_buf = log.write_ahead_buf;
1527
1528 LOG_SYNC_POINT("log_writer_before_copy_to_write_ahead_buffer");
1529 /*复制功能*/
1530 std::memcpy(write_buf, buffer, size);
1531
1532 size_t completed_blocks_size;
1533 byte *incomplete_block;
1534 size_t incomplete_size;
1535 /*写入大小与512向下对齐,得到512的整数*/
1536 completed_blocks_size = ut_uint64_align_down(size, OS_FILE_LOG_BLOCK_SIZE);
1537 /*log.write_ahead_buf redo日志大小 512整数倍的偏移量,之后则为不足512的redo日志,需要特殊处理*/
1538 incomplete_block = write_buf + completed_blocks_size;
1539 /*不足512的大小*/
1540 incomplete_size = size % OS_FILE_LOG_BLOCK_SIZE;
1541
1542 ut_a(incomplete_block + incomplete_size <=
1543 write_buf + srv_log_write_ahead_size);
1544 /*存在不足512的部分*/
1545 if (incomplete_size != 0) {
1546 /* Prepare the incomplete (last) block. */
1547 ut_a(incomplete_size >= LOG_BLOCK_HDR_SIZE);
1548 /*设置当前lsn 为block块的序号*/
1549 log_block_set_hdr_no(
1550 incomplete_block,
1551 log_block_convert_lsn_to_no(start_lsn + completed_blocks_size));
1552 /*记录一次写不足512的情况*/
1553 log_block_set_flush_bit(incomplete_block, completed_blocks_size == 0);
1554 /*记录写入块的实际redo日志的大小*/
1555 log_block_set_data_len(incomplete_block, incomplete_size);
1556
1557 if (log_block_get_first_rec_group(incomplete_block) > incomplete_size) {
1558 log_block_set_first_rec_group(incomplete_block, 0);
1559 }
1560 /*记录当前checkpoint_no的序号*/
1561 log_block_set_checkpoint_no(incomplete_block, checkpoint_no);
1562 /*不足512的剩余部分填充0*/
1563 std::memset(incomplete_block + incomplete_size, 0x00,
1564 OS_FILE_LOG_BLOCK_SIZE - incomplete_size);
1565 /*计算尾部校验数*/
1566 log_block_store_checksum(incomplete_block);
1567 /*返回512的整数倍,保证每次写都是512的倍数,如果不足512,也需要写入512字节*/
1568 size = completed_blocks_size + OS_FILE_LOG_BLOCK_SIZE;
1569 }
1570
1571 /* Since now, size is about completed blocks always. */
1572 ut_a(size % OS_FILE_LOG_BLOCK_SIZE == 0);
1573 }
代码解读-
/*
此处的判断及实现也是非常的经典
当上次把write_ahead 的虚拟空间或者pageCache 写满后的补充处理
实现两个功能
1 如果恰好在ib_logfile 尾部不足一个8192的大小(恰有这样的情况产生,文件的大小减去2048不是8192的倍数,文件大小可以配置,产生不一样的情况,会有很大几率可能出现),则只能使用剩余空间的pageCache的大小
2 本次要写入8192字节大小,剩余的空间需要填充0
此处处理与函数compute_how_much_to_write中的
if (!current_write_ahead_enough(log, real_offset, 1)){
...
}对应,是对此处的完美补充
*/
1689 if (!current_write_ahead_enough(log, real_offset, 1)) {
1690 written_ahead = prepare_for_write_ahead(log, real_offset, write_size);
1691 }
1575 static inline size_t prepare_for_write_ahead(log_t &log, uint64_t real_offset,
1576 size_t &write_size) {
1577 /* We need to perform write ahead during this write. */
1578 /*得到下一个write-ahead尾偏移量*/
1579 const auto next_wa = compute_next_write_ahead_end(real_offset);
1580
1581 ut_a(real_offset + write_size <= next_wa);
1582 /*此write_ahead 8192字节大小中还未使用的部分*/
1583 size_t write_ahead =
1584 static_cast<size_t>(next_wa - (real_offset + write_size));
1585 /*判断当前real_offset 到 ib_logfile 尾部的剩余空间大小是否能写下一个完整的8192的空间的大小,即最后一个pageCache 不一定是8192字节的大小,在当前ib_logfile文件马上要写满时会出现 */
1586 if (!current_file_has_space(log, real_offset, write_size + write_ahead)) {
1587 /* We must not write further than to the end
1588 of the current log file.
1589
1590 Note, that: log.file_size - LOG_FILE_HDR_SIZE
1591 does not have to be divisible by size of write
1592 ahead. Example given:
1593 innodb_log_file_size = 1024M,
1594 innodb_log_write_ahead_size = 4KiB,
1595 LOG_FILE_HDR_SIZE is 2KiB. */
1596 /*
当ib_logfile的最后一个pageCache时,计算出剩余空间
虽然一个8192字节的pageCache 放不下,但是要写redo日志的大小肯定能放得下,
compute_how_much_to_write 此函数已提前处理
*/
1597 write_ahead = static_cast<size_t>(log.current_file_end_offset -
1598 real_offset - write_size);
1599 }
1600
1601 ut_a(current_file_has_space(log, real_offset, write_size + write_ahead));
1602
1603 LOG_SYNC_POINT("log_writer_before_write_ahead");
1604 /*剩余空间填充0*/
1605 std::memset(log.write_ahead_buf + write_size, 0x00, write_ahead);
1606 /*得到pageCache的大小,大多数情况为8192 */
1607 write_size += write_ahead;
1608
1609 return (write_ahead);
1610 }
代码解析- update_current_write_ahead
/*
write-ahead 的pageCache的收官之作
当第一次使用write-ahead,把write-ahead尾部的偏移量write_ahead_end_offset更新为最新的偏移的量,可以理解为加8192(除ib_logfile尾的特殊处理)
*/
1612 static inline void update_current_write_ahead(log_t &log, uint64_t real_offset,
1613 size_t write_size) {
1614 const auto end = real_offset + write_size;
1615
1616 if (end > log.write_ahead_end_offset) {
1617 log.write_ahead_end_offset =
1618 ut_uint64_align_down(end, srv_log_write_ahead_size);
1619 }
1620 }
1621
1622 } // namespace Log_files_write_impl
标签:log,ahead,lsn,write,源码,offset,size 来源: https://blog.csdn.net/qhgxinxing/article/details/110562795