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 GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase {
38 public void testShouldReportZeroObjectsForInitializedRepo()
40 assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap);
44 public void testShouldReportAllPackFilesWhenNoGcWasPerformed()
47 long result = gc.getStatistics().numberOfPackFilesSinceBitmap;
49 assertEquals(repo.getObjectDatabase().getPacks().size(), result);
53 public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception {
57 assertEquals(1L, repositoryBitmapFiles());
58 assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap);
62 public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses()
65 RevCommit parent = addCommit(null);
67 assertEquals(1L, repositoryBitmapFiles());
73 assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap);
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().numberOfPackFilesSinceBitmap);
96 private void packAndPrune() throws Exception {
97 try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository(
99 testRepo.packAndPrune();
103 private RevCommit addCommit(RevCommit parent) throws Exception {
104 PersonIdent ident = new PersonIdent("repo-metrics", "repo@metrics.com");
105 TestRepository<FileRepository>.CommitBuilder builder = tr.commit()
107 if (parent != null) {
108 builder.parent(parent);
110 RevCommit commit = builder.create();
111 tr.update("master", commit);
116 private long repositoryBitmapFiles() throws IOException {
119 .newDirectoryStream(repo.getObjectDatabase()
120 .getPackDirectory().toPath(), "pack-*.bitmap")
121 .spliterator(), false)
126 * The TestRepository has a {@link TestRepository#packAndPrune()} function
127 * but it fails in the last step after GC was performed as it doesn't
128 * SKIP_MISSING files. In order to circumvent it was copied and improved
131 private static class SkipNonExistingFilesTestRepository
132 extends TestRepository<FileRepository> {
133 private final FileRepository repo;
135 private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException {
141 public void packAndPrune() throws Exception {
142 ObjectDirectory odb = repo.getObjectDatabase();
143 NullProgressMonitor m = NullProgressMonitor.INSTANCE;
145 final PackFile pack, idx;
146 try (PackWriter pw = new PackWriter(repo)) {
147 Set<ObjectId> all = new HashSet<>();
148 for (Ref r : repo.getRefDatabase().getRefs())
149 all.add(r.getObjectId());
150 pw.preparePack(m, all, PackWriter.NONE);
152 pack = new PackFile(odb.getPackDirectory(), pw.computeName(),
154 try (OutputStream out = new BufferedOutputStream(
155 new FileOutputStream(pack))) {
156 pw.writePack(m, m, out);
160 idx = pack.create(PackExt.INDEX);
161 try (OutputStream out = new BufferedOutputStream(
162 new FileOutputStream(idx))) {
171 // alternative packAndPrune implementation that skips missing files
173 for (Pack p : odb.getPacks()) {
174 for (MutableEntry e : p)
175 FileUtils.delete(odb.fileFor(e.toObjectId()),
176 FileUtils.SKIP_MISSING);