17
17
namespace bustub {
18
18
19
19
TEST (LRUKReplacerTest, DISABLED_SampleTest) {
20
+ // Note that comparison with `std::nullopt` always results in `false`, and if the optional type actually does contain
21
+ // a value, the comparison will compare the inner value.
22
+ // See: https://devblogs.microsoft.com/oldnewthing/20211004-00/?p=105754
23
+ std::optional<frame_id_t > frame;
24
+
25
+ // Initialize the replacer.
20
26
LRUKReplacer lru_replacer (7 , 2 );
21
27
22
- // Scenario: add six elements to the replacer. We have [1,2,3,4, 5]. Frame 6 is non-evictable.
28
+ // Add six frames to the replacer. We now have frames [1, 2, 3, 4, 5]. We set frame 6 as non-evictable.
23
29
lru_replacer.RecordAccess (1 );
24
30
lru_replacer.RecordAccess (2 );
25
31
lru_replacer.RecordAccess (3 );
@@ -32,25 +38,24 @@ TEST(LRUKReplacerTest, DISABLED_SampleTest) {
32
38
lru_replacer.SetEvictable (4 , true );
33
39
lru_replacer.SetEvictable (5 , true );
34
40
lru_replacer.SetEvictable (6 , false );
41
+
42
+ // The size of the replacer is the number of frames that can be evicted, _not_ the total number of frames entered.
35
43
ASSERT_EQ (5 , lru_replacer.Size ());
36
44
37
- // Scenario: Insert access history for frame 1. Now frame 1 has two access histories.
38
- // All other frames have max backward k-dist. The order of eviction is [2,3,4,5,1].
45
+ // Record an access for frame 1. Now frame 1 has two accesses total.
39
46
lru_replacer.RecordAccess (1 );
47
+ // All other frames now share the maximum backward k-distance. Since we use timestamps to break ties, where the first
48
+ // to be evicted is the frame with the oldest timestamp, the order of eviction should be [2, 3, 4, 5, 1].
40
49
41
- // Scenario: Evict three pages from the replacer. Elements with max k-distance should be popped
42
- // first based on LRU.
43
- int value;
44
- lru_replacer.Evict (&value);
45
- ASSERT_EQ (2 , value);
46
- lru_replacer.Evict (&value);
47
- ASSERT_EQ (3 , value);
48
- lru_replacer.Evict (&value);
49
- ASSERT_EQ (4 , value);
50
+ // Evict three pages from the replacer.
51
+ // To break ties, we use LRU with respect to the oldest timestamp, or the least recently used frame.
52
+ ASSERT_EQ (2 , lru_replacer.Evict ());
53
+ ASSERT_EQ (3 , lru_replacer.Evict ());
54
+ ASSERT_EQ (4 , lru_replacer.Evict ());
50
55
ASSERT_EQ (2 , lru_replacer.Size ());
56
+ // Now the replacer has the frames [5, 1].
51
57
52
- // Scenario: Now replacer has frames [5,1].
53
- // Insert new frames 3, 4, and update access history for 5. We should end with [3,1,5,4]
58
+ // Insert new frames [3, 4], and update the access history for 5. Now, the ordering is [3, 1, 5, 4].
54
59
lru_replacer.RecordAccess (3 );
55
60
lru_replacer.RecordAccess (4 );
56
61
lru_replacer.RecordAccess (5 );
@@ -59,40 +64,59 @@ TEST(LRUKReplacerTest, DISABLED_SampleTest) {
59
64
lru_replacer.SetEvictable (4 , true );
60
65
ASSERT_EQ (4 , lru_replacer.Size ());
61
66
62
- // Scenario: continue looking for victims. We expect 3 to be evicted next.
63
- lru_replacer.Evict (&value);
64
- ASSERT_EQ (3 , value);
67
+ // Look for a frame to evict. We expect frame 3 to be evicted next.
68
+ ASSERT_EQ (3 , lru_replacer.Evict ());
65
69
ASSERT_EQ (3 , lru_replacer.Size ());
66
70
67
- // Set 6 to be evictable. 6 Should be evicted next since it has max backward k-dist .
71
+ // Set 6 to be evictable. 6 Should be evicted next since it has the maximum backward k-distance .
68
72
lru_replacer.SetEvictable (6 , true );
69
73
ASSERT_EQ (4 , lru_replacer.Size ());
70
- lru_replacer.Evict (&value);
71
- ASSERT_EQ (6 , value);
74
+ ASSERT_EQ (6 , lru_replacer.Evict ());
72
75
ASSERT_EQ (3 , lru_replacer.Size ());
73
76
74
- // Now we have [1,5,4]. Continue looking for victims .
77
+ // Mark frame 1 as non-evictable. We now have [5, 4] .
75
78
lru_replacer.SetEvictable (1 , false );
79
+
80
+ // We expect frame 5 to be evicted next.
76
81
ASSERT_EQ (2 , lru_replacer.Size ());
77
- ASSERT_EQ (true , lru_replacer.Evict (&value));
78
- ASSERT_EQ (5 , value);
82
+ ASSERT_EQ (5 , lru_replacer.Evict ());
79
83
ASSERT_EQ (1 , lru_replacer.Size ());
80
84
81
- // Update access history for 1 . Now we have [4,1]. Next victim is 4 .
85
+ // Update the access history for frame 1 and make it evictable . Now we have [4, 1] .
82
86
lru_replacer.RecordAccess (1 );
83
87
lru_replacer.RecordAccess (1 );
84
88
lru_replacer.SetEvictable (1 , true );
85
89
ASSERT_EQ (2 , lru_replacer.Size ());
86
- ASSERT_EQ (true , lru_replacer.Evict (&value));
87
- ASSERT_EQ (value, 4 );
88
90
91
+ // Evict the last two frames.
92
+ ASSERT_EQ (4 , lru_replacer.Evict ());
93
+ ASSERT_EQ (1 , lru_replacer.Size ());
94
+ ASSERT_EQ (1 , lru_replacer.Evict ());
95
+ ASSERT_EQ (0 , lru_replacer.Size ());
96
+
97
+ // Insert frame 1 again and mark it as non-evictable.
98
+ lru_replacer.RecordAccess (1 );
99
+ lru_replacer.SetEvictable (1 , false );
100
+ ASSERT_EQ (0 , lru_replacer.Size ());
101
+
102
+ // A failed eviction should not change the size of the replacer.
103
+ frame = lru_replacer.Evict ();
104
+ ASSERT_EQ (false , frame.has_value ());
105
+
106
+ // Mark frame 1 as evictable again and evict it.
107
+ lru_replacer.SetEvictable (1 , true );
89
108
ASSERT_EQ (1 , lru_replacer.Size ());
90
- lru_replacer.Evict (&value);
91
- ASSERT_EQ (value, 1 );
109
+ ASSERT_EQ (1 , lru_replacer.Evict ());
92
110
ASSERT_EQ (0 , lru_replacer.Size ());
93
111
94
- // This operation should not modify size
95
- ASSERT_EQ (false , lru_replacer.Evict (&value));
112
+ // There is nothing left in the replacer, so make sure this doesn't do something strange.
113
+ frame = lru_replacer.Evict ();
114
+ ASSERT_EQ (false , frame.has_value ());
96
115
ASSERT_EQ (0 , lru_replacer.Size ());
116
+
117
+ // Make sure that setting a non-existent frame as evictable or non-evictable doesn't do something strange.
118
+ lru_replacer.SetEvictable (6 , false );
119
+ lru_replacer.SetEvictable (6 , true );
97
120
}
121
+
98
122
} // namespace bustub
0 commit comments