2 * Copyright (c) 2024 Jacek Centkowski <geminica.programs@gmail.com> and others.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
8 * SPDX-License-Identifier: BSD-3-Clause
11 package org.eclipse.jgit.internal.storage.file;
13 import static org.junit.Assert.assertEquals;
15 import java.io.BufferedOutputStream;
16 import java.io.FileOutputStream;
17 import java.io.IOException;
18 import java.io.OutputStream;
19 import java.nio.file.Files;
20 import java.util.HashSet;
22 import java.util.stream.StreamSupport;
24 import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry;
25 import org.eclipse.jgit.internal.storage.pack.PackExt;
26 import org.eclipse.jgit.internal.storage.pack.PackWriter;
27 import org.eclipse.jgit.junit.TestRepository;
28 import org.eclipse.jgit.lib.NullProgressMonitor;
29 import org.eclipse.jgit.lib.ObjectId;
30 import org.eclipse.jgit.lib.PersonIdent;
31 import org.eclipse.jgit.lib.Ref;
32 import org.eclipse.jgit.revwalk.RevCommit;
33 import org.eclipse.jgit.util.FileUtils;
34 import org.junit.Test;
36 public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase {
38 public void testShouldReportZeroObjectsForInitializedRepo()
40 assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap);
44 public void testShouldReportAllPackFilesWhenNoGcWasPerformed()
47 long result = gc.getStatistics().numberOfPackFilesAfterBitmap;
49 assertEquals(repo.getObjectDatabase().getPacks().size(), result);
53 public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception {
57 assertEquals(1L, repositoryBitmapFiles());
58 assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap);
62 public void testShouldReportNewObjectsAfterGcWhenRepositoryProgresses()
65 RevCommit parent = addCommit(null);
67 assertEquals(1L, repositoryBitmapFiles());
73 assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap);
77 public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses()
80 RevCommit parent = addCommit(null);
82 assertEquals(1L, repositoryBitmapFiles());
85 parent = addCommit(parent);
87 assertEquals(2L, repositoryBitmapFiles());
93 assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap);
96 private void packAndPrune() throws Exception {
97 try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository(
99 testRepo.packAndPrune();
103 private RevCommit addCommit(RevCommit parent) throws Exception {
104 return tr.branch("master").commit()
105 .author(new PersonIdent("repo-metrics", "repo@metrics.com"))
106 .parent(parent).create();
109 private long repositoryBitmapFiles() throws IOException {
112 .newDirectoryStream(repo.getObjectDatabase()
113 .getPackDirectory().toPath(), "pack-*.bitmap")
114 .spliterator(), false)
119 * The TestRepository has a {@link TestRepository#packAndPrune()} function
120 * but it fails in the last step after GC was performed as it doesn't
121 * SKIP_MISSING files. In order to circumvent it was copied and improved
124 private static class SkipNonExistingFilesTestRepository
125 extends TestRepository<FileRepository> {
126 private final FileRepository repo;
128 private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException {
134 public void packAndPrune() throws Exception {
135 ObjectDirectory odb = repo.getObjectDatabase();
136 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
138 final PackFile pack, idx;
139 try (PackWriter pw = new PackWriter(repo)) {
140 Set<ObjectId> all = new HashSet<>();
141 for (Ref r : repo.getRefDatabase().getRefs())
142 all.add(r.getObjectId());
143 pw.preparePack(m, all, PackWriter.NONE);
145 pack = new PackFile(odb.getPackDirectory(), pw.computeName(),
147 try (OutputStream out = new BufferedOutputStream(
148 new FileOutputStream(pack))) {
149 pw.writePack(m, m, out);
153 idx = pack.create(PackExt.INDEX);
154 try (OutputStream out = new BufferedOutputStream(
155 new FileOutputStream(idx))) {
164 // alternative packAndPrune implementation that skips missing files
166 for (Pack p : odb.getPacks()) {
167 for (MutableEntry e : p)
168 FileUtils.delete(odb.fileFor(e.toObjectId()),
169 FileUtils.SKIP_MISSING);