From 181b629f7deea1750b8e5d2160750ed2cef91c3d Mon Sep 17 00:00:00 2001 From: Anna Papitto Date: Tue, 30 May 2023 16:20:54 +0200 Subject: [PATCH] Gc#writePack: write the reverse index file to disk The reverse index is currently created in-memory when needed. A writer for reverse index files was already implemented. Make garbage collection write the reverse index file when the PackConfig enables it. Write it during #writePack, which mirrors how the primary index is written. Change-Id: I50131af6622c41a7b24534aaaf2a423ab4178981 Signed-off-by: Anna Papitto --- .../storage/file/GcReverseIndexTest.java | 116 ++++++++++++++++++ .../jgit/internal/storage/file/GC.java | 19 +++ 2 files changed, 135 insertions(+) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReverseIndexTest.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReverseIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReverseIndexTest.java new file mode 100644 index 000000000..cbb094342 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReverseIndexTest.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2023, Google LLC and others + * + * 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.internal.storage.file; + +import static org.eclipse.jgit.internal.storage.pack.PackExt.REVERSE_INDEX; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Collections; + +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.storage.pack.PackConfig; +import org.eclipse.jgit.util.IO; +import org.junit.Test; + +public class GcReverseIndexTest extends GcTestCase { + + @Test + public void testWriteDefault() throws Exception { + PackConfig config = new PackConfig(repo); + gc.setPackConfig(config); + + RevCommit tip = commitChain(10); + TestRepository.BranchBuilder bb = tr.branch("refs/heads/main"); + bb.update(tip); + + gc.gc().get(); + assertRidxDoesNotExist(repo); + } + + @Test + public void testWriteDisabled() throws Exception { + PackConfig config = new PackConfig(repo); + config.setWriteReverseIndex(false); + gc.setPackConfig(config); + + RevCommit tip = commitChain(10); + TestRepository.BranchBuilder bb = tr.branch("refs/heads/main"); + bb.update(tip); + + gc.gc().get(); + assertRidxDoesNotExist(repo); + } + + @Test + public void testWriteEmptyRepo() throws Exception { + PackConfig config = new PackConfig(repo); + config.setWriteReverseIndex(true); + gc.setPackConfig(config); + + gc.gc().get(); + assertRidxDoesNotExist(repo); + } + + @Test + public void testWriteShallowRepo() throws Exception { + PackConfig config = new PackConfig(repo); + config.setWriteReverseIndex(true); + gc.setPackConfig(config); + + RevCommit tip = commitChain(2); + TestRepository.BranchBuilder bb = tr.branch("refs/heads/main"); + bb.update(tip); + repo.getObjectDatabase().setShallowCommits(Collections.singleton(tip)); + + gc.gc().get(); + assertValidRidxExists(repo); + } + + @Test + public void testWriteEnabled() throws Exception { + PackConfig config = new PackConfig(repo); + config.setWriteReverseIndex(true); + gc.setPackConfig(config); + + RevCommit tip = commitChain(10); + TestRepository.BranchBuilder bb = tr.branch("refs/heads/main"); + bb.update(tip); + + gc.gc().get(); + assertValidRidxExists(repo); + } + + private static void assertValidRidxExists(FileRepository repo) + throws Exception { + PackFile packFile = repo.getObjectDatabase().getPacks().iterator() + .next().getPackFile(); + File file = packFile.create(REVERSE_INDEX); + assertTrue(file.exists()); + try (InputStream os = new FileInputStream(file)) { + byte[] magic = new byte[4]; + IO.readFully(os, magic, 0, 4); + assertArrayEquals(new byte[] { 'R', 'I', 'D', 'X' }, magic); + } + } + + private static void assertRidxDoesNotExist(FileRepository repo) { + File packDir = repo.getObjectDatabase().getPackDirectory(); + String[] reverseIndexFilenames = packDir.list( + (dir, name) -> name.endsWith(REVERSE_INDEX.getExtension())); + assertEquals(0, reverseIndexFilenames.length); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index 11757aabd..10b53b666 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -1323,6 +1323,25 @@ private Pack writePack(@NonNull Set want, idxChannel.force(true); } + if (pw.isReverseIndexEnabled()) { + File tmpReverseIndexFile = new File(packdir, + tmpBase + REVERSE_INDEX.getTmpExtension()); + tmpExts.put(REVERSE_INDEX, tmpReverseIndexFile); + if (!tmpReverseIndexFile.createNewFile()) { + throw new IOException(MessageFormat.format( + JGitText.get().cannotCreateIndexfile, + tmpReverseIndexFile.getPath())); + } + try (FileOutputStream fos = new FileOutputStream( + tmpReverseIndexFile); + FileChannel channel = fos.getChannel(); + OutputStream stream = Channels + .newOutputStream(channel)) { + pw.writeReverseIndex(stream); + channel.force(true); + } + } + if (pw.prepareBitmapIndex(pm)) { File tmpBitmapIdx = new File(packdir, tmpBase + BITMAP_INDEX.getTmpExtension());