/* * Copyright (C) 2023, Google Inc. * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.revwalk; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.util.List; import org.eclipse.jgit.internal.storage.file.FileRepository; import org.eclipse.jgit.internal.storage.file.GC; import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.BitmapIndex; import org.eclipse.jgit.lib.BitmapIndex.Bitmap; import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder; import org.eclipse.jgit.lib.BitmapIndex.BitmapLookupListener; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectReader; import org.junit.Before; import org.junit.Test; public class BitmapWalkerTest extends LocalDiskRepositoryTestCase { private static final String MAIN = "refs/heads/main"; TestRepository repo; RevCommit tipWithBitmap; @Override @Before public void setUp() throws Exception { super.setUp(); FileRepository db = createWorkRepository(); repo = new TestRepository<>(db); RevCommit base = repo.commit().create(); RevCommit one = repo.commit().parent(base).create(); tipWithBitmap = repo.commit().parent(one).create(); repo.update(MAIN, tipWithBitmap); GC gc = new GC(repo.getRepository()); gc.setAuto(false); gc.gc().get(); assertNotNull(repo.getRevWalk().getObjectReader().getBitmapIndex()); } private static class BitmapWalkCounter implements BitmapLookupListener { int withBitmap; int withoutBitmap; @Override public void onBitmapFound(AnyObjectId oid) { withBitmap += 1; } @Override public void onBitmapNotFound(AnyObjectId oid) { withoutBitmap += 1; } } @Test public void counters_bitmapAtTip() throws Exception { try (RevWalk rw = repo.getRevWalk(); ObjectReader or = rw.getObjectReader()) { BitmapWalkCounter counter = new BitmapWalkCounter(); BitmapIndex bitmapIndex = or.getBitmapIndex(); bitmapIndex.addBitmapLookupListener(counter); BitmapWalker bw = new BitmapWalker(rw.toObjectWalkWithSameObjects(), bitmapIndex, NullProgressMonitor.INSTANCE); BitmapBuilder bitmap = bw.findObjects(List.of(tipWithBitmap), null, true); // First commit has a tree, so in total 4 objects assertEquals(4, bitmap.cardinality()); assertEquals(1, counter.withBitmap); assertEquals(0, counter.withoutBitmap); assertEquals(0, bw.getCountOfBitmapIndexMisses()); } } @Test public void counters_bitmapAfterAStep() throws Exception { System.out.println("Old tip: " + tipWithBitmap); RevCommit newTip = repo.commit().parent(tipWithBitmap).create(); System.out.println("New tip: " + newTip); try (RevWalk rw = repo.getRevWalk(); ObjectReader or = rw.getObjectReader()) { BitmapWalkCounter counter = new BitmapWalkCounter(); BitmapIndex bitmapIndex = or.getBitmapIndex(); bitmapIndex.addBitmapLookupListener(counter); BitmapWalker bw = new BitmapWalker(rw.toObjectWalkWithSameObjects(), bitmapIndex, NullProgressMonitor.INSTANCE); bw.findObjects(List.of(newTip), null, true); assertEquals(1, counter.withBitmap); // It checks bitmap before marking as interesting, and again in the // walk assertEquals(2, counter.withoutBitmap); assertEquals(1, bw.getCountOfBitmapIndexMisses()); } } @Test public void counters_bitmapAfterThreeSteps() throws Exception { RevCommit newOne = repo.commit().parent(tipWithBitmap).create(); RevCommit newTwo = repo.commit().parent(newOne).create(); RevCommit newTip = repo.commit().parent(newTwo).create(); try (RevWalk rw = repo.getRevWalk(); ObjectReader or = rw.getObjectReader()) { BitmapWalkCounter counter = new BitmapWalkCounter(); BitmapIndex bitmapIndex = or.getBitmapIndex(); bitmapIndex.addBitmapLookupListener(counter); BitmapWalker bw = new BitmapWalker(rw.toObjectWalkWithSameObjects(), bitmapIndex, NullProgressMonitor.INSTANCE); bw.findObjects(List.of(newTip), null, true); assertEquals(1, counter.withBitmap); assertEquals(4, counter.withoutBitmap); assertEquals(3, bw.getCountOfBitmapIndexMisses()); } } @Test public void counters_bitmapAfterThreeStepsWithSeen() throws Exception { RevCommit newOne = repo.commit().parent(tipWithBitmap).create(); RevCommit newTwo = repo.commit().parent(newOne).create(); RevCommit newTip = repo.commit().parent(newTwo).create(); try (RevWalk rw = repo.getRevWalk(); ObjectReader or = rw.getObjectReader()) { BitmapIndex bitmapIndex = or.getBitmapIndex(); Bitmap seen = bitmapIndex.getBitmap(tipWithBitmap); BitmapBuilder seenBB = bitmapIndex.newBitmapBuilder().or(seen); BitmapWalkCounter counter = new BitmapWalkCounter(); bitmapIndex.addBitmapLookupListener(counter); BitmapWalker bw = new BitmapWalker(rw.toObjectWalkWithSameObjects(), bitmapIndex, NullProgressMonitor.INSTANCE); bw.findObjects(List.of(newTip), seenBB, true); assertEquals(0, counter.withBitmap); assertEquals(4, counter.withoutBitmap); assertEquals(3, bw.getCountOfBitmapIndexMisses()); } } }