SLRU页面选择函数SlruSelectLRUPage:选择一个空的或淘汰一个SLOT(可能触发IO),返回一个可用SLOT
static int
SlruSelectLRUPage(SlruCtl ctl, int pageno)
{
SlruShared shared = ctl->shared;
/* Outer loop handles restart after I/O */
for (;;)
{
int slotno;
int cur_count;
int bestvalidslot = 0; /* keep compiler quiet */
int best_valid_delta = -1;
int best_valid_page_number = 0; /* keep compiler quiet */
int bestinvalidslot = 0; /* keep compiler quiet */
int best_invalid_delta = -1;
int best_invalid_page_number = 0; /* keep compiler quiet */
// 已经分配过了直接使用
for (slotno = 0; slotno < shared->num_slots; slotno++)
{
if (shared->page_number[slotno] == pageno &&
shared->page_status[slotno] != SLRU_PAGE_EMPTY)
return slotno;
}
// 没有找到已经分配的SLOT,开始O(n)找SLOT
// 总体原则:先找空的、再找用的少的&&不是last刚使用的&&没在IO的,返回
cur_count = (shared->cur_lru_count)++;
for (slotno = 0; slotno < shared->num_slots; slotno++)
{
int this_delta;
int this_page_number;
// 如果是空的直接使用
if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
return slotno;
// 计算差值,差值最大的表示最旧没用到的
// 每次使用都会把shared->page_lru_count[slotno]值刷到shared->cur_lru_count的最新值
this_delta = cur_count - shared->page_lru_count[slotno];
if (this_delta < 0)
{
shared->page_lru_count[slotno] = cur_count;
this_delta = 0;
}
this_page_number = shared->page_number[slotno];
if (this_page_number == shared->latest_page_number)
continue;
// 记录最大差值到best_valid_delta
// 记录最大差值的页面到best_valid_page_number
if (shared->page_status[slotno] == SLRU_PAGE_VALID)
{
if (this_delta > best_valid_delta ||
(this_delta == best_valid_delta &&
ctl->PagePrecedes(this_page_number,
best_valid_page_number)))
{
bestvalidslot = slotno;
best_valid_delta = this_delta;
best_valid_page_number = this_page_number;
}
}
else
{
if (this_delta > best_invalid_delta ||
(this_delta == best_invalid_delta &&
ctl->PagePrecedes(this_page_number,
best_invalid_page_number)))
{
bestinvalidslot = slotno;
best_invalid_delta = this_delta;
best_invalid_page_number = this_page_number;
}
}
}
// 最大差值一直没有被赋值
// 说明所有页面都是非FREE、非VALID状态,全部在IO中
// 需要等IO
if (best_valid_delta < 0)
{
SimpleLruWaitIO(ctl, bestinvalidslot);
continue;
}
// 如果页面没有被修改过,直接使用
if (!shared->page_dirty[bestvalidslot])
return bestvalidslot;
// 页面VALID、被修改过,需要IO到磁盘上
SlruInternalWritePage(ctl, bestvalidslot, NULL);
}
}
GDB脚本看下54页面刚用完,55页面开始使用的情况下,几个关键变量的变化
GDB
define lp9
set $total = shared->num_slots
set $i = 0
while($i<$total)
printf "(%2d) ", $i
printf "(%2d) ", shared->page_number[$i]
printf "(%d) ", shared->page_status[$i]
printf "(%d)\n", shared->page_lru_count[$i]
set $i = $i + 1
end
end
结果
SlruSelectLRUPage(pageno=55)
slotno page_number[slotno] shared->page_status[slotno] shared->page_lru_count[slotno] shared->page_lru_count[slotno] (newpage55)
( 0) ( 4) (2) (1770127) (1770127)
( 1) ( 1) (2) ( 11) ( 11)
( 2) ( 0) (2) ( 6) ( 6)
( 3) ( 5) (2) ( 894332) ( 894332)
( 4) ( 6) (2) ( 911112) ( 911112)
( 5) ( 7) (2) (1755207) (1755207)
( 6) ( 8) (2) (1448227) (1448227)
( 7) ( 9) (2) (1633175) (1633175)
( 8) (10) (2) (1455242) (1455242)
( 9) (11) (2) (1633187) (1633187)
(10) (12) (2) (1633177) (1633177)
(11) (13) (2) (1278375) (1278375)
(12) (14) (2) (1657380) (1657380)
(13) (15) (2) (1126074) (1126074)
(14) (16) (2) (1669976) (1669976)
(15) (17) (2) (1721254) (1721254)
(16) (18) (2) (1207329) (1207329)
(17) (19) (2) (1606693) (1606693)
(18) (20) (2) (1705478) (1705478)
(19) (21) (2) (1379095) (1379095)
(20) (22) (2) (1633183) (1633183)
(21) (23) (2) (1768703) (1768703)
(22) (24) (2) (1769738) (1769738)
(23) (25) (2) (1769806) (1769806)
(24) (26) (2) (1769982) (1769982)
(25) (27) (2) (1769271) (1769271)
(26) (28) (2) (1770066) (1770066)
(27) (29) (2) (1768997) (1768997)
(28) (30) (2) (1769748) (1769748)
(29) (31) (2) (1769408) (1769408)
(30) (32) (2) (1769880) (1769880)
(31) (33) (2) (1769997) (1769997)
(32) (34) (2) (1769818) (1769818)
(33) (35) (2) (1769992) (1769992)
(34) (36) (2) (1769564) (1769564)
(35) (37) (2) (1770077) (1770077)
(36) (38) (2) (1770097) (1770097)
(37) (39) (2) (1770111) (1770111)
(38) (40) (2) (1770075) (1770075)
(39) (41) (2) (1770067) (1770067)
(40) (42) (2) (1770098) (1770098)
(41) (43) (2) (1770072) (1770072)
(42) (44) (2) (1770065) (1770065)
(43) (45) (2) (1770119) (1770119)
(44) (46) (2) (1770070) (1770070)
(45) (47) (2) (1770123) (1770123)
(46) (48) (2) (1770088) (1770088)
(47) (49) (2) (1770117) (1770117)
(48) (50) (2) (1770120) (1770120)
(49) (51) (2) (1770122) (1770122)
(50) (52) (2) (1770107) (1770107)
(51) (53) (2) (1770121) (1770121)
(52) (54) (2) (1770128) (1770128)
(53) ( 0) -> (55) (0) -> (2) ( 0) -> (1770130) (1770130)
(54) ( 0) (0) ( 0) ( 0)
(55) ( 0) (0) ( 0) ( 0)