]> source.dussan.org Git - jgit.git/blob
42b99ae512b58fe321d6a979ef57276459b6f2be
[jgit.git] /
1 /*
2  * Copyright (c) 2024 Jacek Centkowski <geminica.programs@gmail.com> and others.
3  *
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.
7  *
8  * SPDX-License-Identifier: BSD-3-Clause
9  */
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import static org.junit.Assert.assertEquals;
14
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;
21 import java.util.Set;
22 import java.util.stream.StreamSupport;
23
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;
35
36 public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase {
37         @Test
38         public void testShouldReportZeroObjectsForInitializedRepo()
39                         throws IOException {
40                 assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap);
41         }
42
43         @Test
44         public void testShouldReportAllPackFilesWhenNoGcWasPerformed()
45                         throws Exception {
46                 packAndPrune();
47                 long result = gc.getStatistics().numberOfPackFilesSinceBitmap;
48
49                 assertEquals(repo.getObjectDatabase().getPacks().size(), result);
50         }
51
52         @Test
53         public void testShouldReportNoObjectsDirectlyAfterGc() throws Exception {
54                 // given
55                 addCommit(null);
56                 gc.gc().get();
57                 assertEquals(1L, repositoryBitmapFiles());
58                 assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap);
59         }
60
61         @Test
62         public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses()
63                         throws Exception {
64                 // commit & gc
65                 RevCommit parent = addCommit(null);
66                 gc.gc().get();
67                 assertEquals(1L, repositoryBitmapFiles());
68
69                 // progress & pack
70                 addCommit(parent);
71                 packAndPrune();
72
73                 assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap);
74         }
75
76         @Test
77         public void testShouldReportNewObjectsFromTheLatestBitmapWhenRepositoryProgresses()
78                         throws Exception {
79                 // commit & gc
80                 RevCommit parent = addCommit(null);
81                 gc.gc().get();
82                 assertEquals(1L, repositoryBitmapFiles());
83
84                 // progress & gc
85                 parent = addCommit(parent);
86                 gc.gc().get();
87                 assertEquals(2L, repositoryBitmapFiles());
88
89                 // progress & pack
90                 addCommit(parent);
91                 packAndPrune();
92
93                 assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap);
94         }
95
96         private void packAndPrune() throws Exception {
97                 try (SkipNonExistingFilesTestRepository testRepo = new SkipNonExistingFilesTestRepository(
98                                 repo)) {
99                         testRepo.packAndPrune();
100                 }
101         }
102
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()
106                                 .author(ident);
107                 if (parent != null) {
108                         builder.parent(parent);
109                 }
110                 RevCommit commit = builder.create();
111                 tr.update("master", commit);
112                 parent = commit;
113                 return parent;
114         }
115
116         private long repositoryBitmapFiles() throws IOException {
117                 return StreamSupport
118                                 .stream(Files
119                                                 .newDirectoryStream(repo.getObjectDatabase()
120                                                                 .getPackDirectory().toPath(), "pack-*.bitmap")
121                                                 .spliterator(), false)
122                                 .count();
123         }
124
125         /**
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
129          * here.
130          */
131         private static class SkipNonExistingFilesTestRepository
132                         extends TestRepository<FileRepository> {
133                 private final FileRepository repo;
134
135                 private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException {
136                         super(db);
137                         repo = db;
138                 }
139
140                 @Override
141                 public void packAndPrune() throws Exception {
142                         ObjectDirectory odb = repo.getObjectDatabase();
143                         NullProgressMonitor m = NullProgressMonitor.INSTANCE;
144
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);
151
152                                 pack = new PackFile(odb.getPackDirectory(), pw.computeName(),
153                                                 PackExt.PACK);
154                                 try (OutputStream out = new BufferedOutputStream(
155                                                 new FileOutputStream(pack))) {
156                                         pw.writePack(m, m, out);
157                                 }
158                                 pack.setReadOnly();
159
160                                 idx = pack.create(PackExt.INDEX);
161                                 try (OutputStream out = new BufferedOutputStream(
162                                                 new FileOutputStream(idx))) {
163                                         pw.writeIndex(out);
164                                 }
165                                 idx.setReadOnly();
166                         }
167
168                         odb.openPack(pack);
169                         updateServerInfo();
170
171                         // alternative packAndPrune implementation that skips missing files
172                         // after GC.
173                         for (Pack p : odb.getPacks()) {
174                                 for (MutableEntry e : p)
175                                         FileUtils.delete(odb.fileFor(e.toObjectId()),
176                                                         FileUtils.SKIP_MISSING);
177                         }
178                 }
179         }
180 }