Skip to content

Commit a1a0ad3

Browse files
authored
Hotfix: add new ARC Replacer test (#869)
New test is for verifying the behavior of remove
1 parent 1c4c0ea commit a1a0ad3

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

test/buffer/arc_replacer_test.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,163 @@ TEST(ArcReplacerTest, DISABLED_SampleTest2) {
214214
ASSERT_EQ(1, arc_replacer.Evict());
215215
}
216216

217+
TEST(ArcReplacerTest, DISABLED_RemoveBehaviorTest) {
218+
// Scenario 1: Remove from empty replacer — should be a no-op
219+
{
220+
ArcReplacer arc_replacer(5);
221+
arc_replacer.Remove(0);
222+
ASSERT_EQ(0, arc_replacer.Size());
223+
}
224+
225+
// Scenario 2: Remove a non-existent frame_id — should be a no-op
226+
{
227+
ArcReplacer arc_replacer(5);
228+
arc_replacer.RecordAccess(0, 10);
229+
arc_replacer.SetEvictable(0, true);
230+
ASSERT_EQ(1, arc_replacer.Size());
231+
arc_replacer.Remove(99); // never inserted
232+
ASSERT_EQ(1, arc_replacer.Size());
233+
}
234+
235+
// Scenario 3: Remove an evictable frame from MRU
236+
{
237+
ArcReplacer arc_replacer(5);
238+
arc_replacer.RecordAccess(0, 10);
239+
arc_replacer.SetEvictable(0, true);
240+
arc_replacer.RecordAccess(1, 11);
241+
arc_replacer.SetEvictable(1, true);
242+
arc_replacer.RecordAccess(2, 12);
243+
arc_replacer.SetEvictable(2, true);
244+
// State: [][(10,f0),(11,f1),(12,f2)]![][] p=0
245+
ASSERT_EQ(3, arc_replacer.Size());
246+
247+
arc_replacer.Remove(1); // remove middle frame from MRU
248+
ASSERT_EQ(2, arc_replacer.Size());
249+
250+
// Evict remaining: should be f0 then f2 (oldest to newest in MRU)
251+
ASSERT_EQ(0, arc_replacer.Evict());
252+
ASSERT_EQ(2, arc_replacer.Evict());
253+
ASSERT_FALSE(arc_replacer.Evict().has_value());
254+
}
255+
256+
// Scenario 4: Remove an evictable frame from MFU
257+
{
258+
ArcReplacer arc_replacer(4);
259+
arc_replacer.RecordAccess(0, 20);
260+
arc_replacer.SetEvictable(0, true);
261+
arc_replacer.RecordAccess(1, 21);
262+
arc_replacer.SetEvictable(1, true);
263+
// Move frame 0 to MFU by accessing again
264+
arc_replacer.RecordAccess(0, 20);
265+
// State: [][(21,f1)]![(20,f0)][] p=0
266+
ASSERT_EQ(2, arc_replacer.Size());
267+
268+
arc_replacer.Remove(0); // remove from MFU
269+
ASSERT_EQ(1, arc_replacer.Size());
270+
271+
// Only frame 1 remains
272+
ASSERT_EQ(1, arc_replacer.Evict());
273+
ASSERT_FALSE(arc_replacer.Evict().has_value());
274+
}
275+
276+
// Scenario 5: Remove does NOT create ghost entries
277+
// If Evict were used instead of Remove, page_id 30 would go into a ghost list.
278+
// On re-access, it would be a ghost hit → placed in MFU and target size adjusted.
279+
// With Remove, no ghost is created → re-access goes to MRU as a fresh entry.
280+
{
281+
ArcReplacer arc_replacer(3);
282+
arc_replacer.RecordAccess(0, 30);
283+
arc_replacer.SetEvictable(0, true);
284+
arc_replacer.RecordAccess(1, 31);
285+
arc_replacer.SetEvictable(1, true);
286+
arc_replacer.RecordAccess(2, 32);
287+
arc_replacer.SetEvictable(2, true);
288+
// State: [][(30,f0),(31,f1),(32,f2)]![][] p=0
289+
290+
// Remove frame 0 (page 30) — no ghost created
291+
arc_replacer.Remove(0);
292+
ASSERT_EQ(2, arc_replacer.Size());
293+
// State: [][(31,f1),(32,f2)]![][] p=0
294+
295+
// Re-add frame 0 with the same page_id 30.
296+
// Since no ghost exists, this is Case IV (miss all lists) → goes to MRU.
297+
arc_replacer.RecordAccess(0, 30);
298+
arc_replacer.SetEvictable(0, true);
299+
// State: [][(31,f1),(32,f2),(30,f0)]![][] p=0
300+
301+
// Evict order from MRU (target=0, all in MRU): f1, f2, f0
302+
ASSERT_EQ(1, arc_replacer.Evict());
303+
ASSERT_EQ(2, arc_replacer.Evict());
304+
ASSERT_EQ(0, arc_replacer.Evict());
305+
}
306+
307+
// Scenario 6: Double remove (same frame_id twice)
308+
{
309+
ArcReplacer arc_replacer(3);
310+
arc_replacer.RecordAccess(0, 40);
311+
arc_replacer.SetEvictable(0, true);
312+
ASSERT_EQ(1, arc_replacer.Size());
313+
314+
arc_replacer.Remove(0);
315+
ASSERT_EQ(0, arc_replacer.Size());
316+
317+
// Second remove is a no-op (frame no longer in alive_map_)
318+
arc_replacer.Remove(0);
319+
ASSERT_EQ(0, arc_replacer.Size());
320+
}
321+
322+
// Scenario 7: Remove then re-insert same frame with a different page_id
323+
{
324+
ArcReplacer arc_replacer(3);
325+
arc_replacer.RecordAccess(0, 50);
326+
arc_replacer.SetEvictable(0, true);
327+
328+
arc_replacer.Remove(0);
329+
ASSERT_EQ(0, arc_replacer.Size());
330+
331+
// Re-use frame 0 with a new page
332+
arc_replacer.RecordAccess(0, 51);
333+
arc_replacer.SetEvictable(0, true);
334+
ASSERT_EQ(1, arc_replacer.Size());
335+
ASSERT_EQ(0, arc_replacer.Evict());
336+
}
337+
338+
// Scenario 8: Remove middle frame preserves eviction order of remaining frames
339+
{
340+
ArcReplacer arc_replacer(5);
341+
for (int i = 0; i < 5; i++) {
342+
arc_replacer.RecordAccess(i, 60 + i);
343+
arc_replacer.SetEvictable(i, true);
344+
}
345+
// MRU: [(60,f0),(61,f1),(62,f2),(63,f3),(64,f4)]
346+
arc_replacer.Remove(2);
347+
ASSERT_EQ(4, arc_replacer.Size());
348+
349+
// Evict order: f0, f1, f3, f4 (frame 2 skipped)
350+
ASSERT_EQ(0, arc_replacer.Evict());
351+
ASSERT_EQ(1, arc_replacer.Evict());
352+
ASSERT_EQ(3, arc_replacer.Evict());
353+
ASSERT_EQ(4, arc_replacer.Evict());
354+
ASSERT_FALSE(arc_replacer.Evict().has_value());
355+
}
356+
357+
// Scenario 9: Remove all frames one by one
358+
{
359+
ArcReplacer arc_replacer(5);
360+
for (int i = 0; i < 5; i++) {
361+
arc_replacer.RecordAccess(i, 80 + i);
362+
arc_replacer.SetEvictable(i, true);
363+
}
364+
ASSERT_EQ(5, arc_replacer.Size());
365+
366+
for (int i = 0; i < 5; i++) {
367+
arc_replacer.Remove(i);
368+
}
369+
ASSERT_EQ(0, arc_replacer.Size());
370+
ASSERT_FALSE(arc_replacer.Evict().has_value());
371+
}
372+
}
373+
217374
// Feel free to write more tests!
218375

219376
} // namespace bustub

0 commit comments

Comments
 (0)