]> source.dussan.org Git - jgit.git/blob
e5a391f2e322de54fbc2ce49c71d03ff029253fb
[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 GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase {
37         @Test
38         public void testShouldReportZeroObjectsForInitializedRepo()
39                         throws IOException {
40                 assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap);
41         }
42
43         @Test
44         public void testShouldReportAllPackFilesWhenNoGcWasPerformed()
45                         throws Exception {
46                 packAndPrune();
47                 long result = gc.getStatistics().numberOfPackFilesAfterBitmap;
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().numberOfPackFilesAfterBitmap);
59         }
60
61         @Test
62         public void testShouldReportNewObjectsAfterGcWhenRepositoryProgresses()
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().numberOfPackFilesAfterBitmap);
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().numberOfPackFilesAfterBitmap);
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                 return tr.branch("master").commit()
105                                 .author(new PersonIdent("repo-metrics", "repo@metrics.com"))
106                                 .parent(parent).create();
107         }
108
109         private long repositoryBitmapFiles() throws IOException {
110                 return StreamSupport
111                                 .stream(Files
112                                                 .newDirectoryStream(repo.getObjectDatabase()
113                                                                 .getPackDirectory().toPath(), "pack-*.bitmap")
114                                                 .spliterator(), false)
115                                 .count();
116         }
117
118         /**
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
122          * here.
123          */
124         private static class SkipNonExistingFilesTestRepository
125                         extends TestRepository<FileRepository> {
126                 private final FileRepository repo;
127
128                 private SkipNonExistingFilesTestRepository(FileRepository db) throws IOException {
129                         super(db);
130                         repo = db;
131                 }
132
133                 @Override
134                 public void packAndPrune() throws Exception {
135                         ObjectDirectory odb = repo.getObjectDatabase();
136                         NullProgressMonitor m = NullProgressMonitor.INSTANCE;
137
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);
144
145                                 pack = new PackFile(odb.getPackDirectory(), pw.computeName(),
146                                                 PackExt.PACK);
147                                 try (OutputStream out = new BufferedOutputStream(
148                                                 new FileOutputStream(pack))) {
149                                         pw.writePack(m, m, out);
150                                 }
151                                 pack.setReadOnly();
152
153                                 idx = pack.create(PackExt.INDEX);
154                                 try (OutputStream out = new BufferedOutputStream(
155                                                 new FileOutputStream(idx))) {
156                                         pw.writeIndex(out);
157                                 }
158                                 idx.setReadOnly();
159                         }
160
161                         odb.openPack(pack);
162                         updateServerInfo();
163
164                         // alternative packAndPrune implementation that skips missing files
165                         // after GC.
166                         for (Pack p : odb.getPacks()) {
167                                 for (MutableEntry e : p)
168                                         FileUtils.delete(odb.fileFor(e.toObjectId()),
169                                                         FileUtils.SKIP_MISSING);
170                         }
171                 }
172         }
173 }