* master: Manually set status of jmh dependencies Update DEPENDENCIES report for 5.11.0 Add dependency to dash-licenses PackFile: Add id + ext based constructors GC: deleteOrphans: Use PackFile PackExt: Convert to Enum Restore preserved packs during missing object seeks Pack: Replace extensions bitset with bitmapIdx PackFile PackDirectory: Use PackFile to ensure we find preserved packs GC: Use PackFile to de-dup logic Create a PackFile class for Pack filenames Change-Id: I1d56517cb6a95e10aed22cdb9e5f3e504872d110tags/v5.11.0.202103091610-r
@@ -0,0 +1,66 @@ | |||
maven/mavencentral/args4j/args4j/2.33, MIT, approved, CQ11068 | |||
maven/mavencentral/com.google.code.gson/gson/2.8.6, Apache-2.0, approved, CQ23102 | |||
maven/mavencentral/com.googlecode.javaewah/JavaEWAH/1.1.7, Apache-2.0, approved, CQ11658 | |||
maven/mavencentral/com.jcraft/jsch/0.1.55, BSD-3-Clause, approved, CQ19435 | |||
maven/mavencentral/com.jcraft/jzlib/1.1.1, BSD-2-Clause, approved, CQ6218 | |||
maven/mavencentral/commons-codec/commons-codec/1.11, Apache-2.0, approved, CQ15971 | |||
maven/mavencentral/commons-logging/commons-logging/1.2, Apache-2.0, approved, CQ10162 | |||
maven/mavencentral/javax.servlet/javax.servlet-api/3.1.0, Apache-2.0 AND (CDDL-1.1 OR GPL-2.0 WITH Classpath-exception-2.0), approved, emo_ip_team | |||
maven/mavencentral/junit/junit/4.13, , approved, CQ22796 | |||
maven/mavencentral/log4j/log4j/1.2.15, Apache-2.0, approved, CQ7837 | |||
maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.9.0, Apache-2.0, approved, clearlydefined | |||
maven/mavencentral/net.bytebuddy/byte-buddy/1.9.0, Apache-2.0, approved, clearlydefined | |||
maven/mavencentral/net.i2p.crypto/eddsa/0.3.0, CC0, approved, CQ17804 | |||
maven/mavencentral/net.sf.jopt-simple/jopt-simple/4.6, MIT, approved, clearlydefined | |||
maven/mavencentral/org.apache.ant/ant-launcher/1.10.8, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560 | |||
maven/mavencentral/org.apache.ant/ant/1.10.8, Apache-2.0 AND W3C AND LicenseRef-Public-Domain, approved, CQ15560 | |||
maven/mavencentral/org.apache.commons/commons-compress/1.19, Apache-2.0, approved, clearlydefined | |||
maven/mavencentral/org.apache.commons/commons-math3/3.2, Apache-2.0, approved, clearlydefined | |||
maven/mavencentral/org.apache.httpcomponents/httpclient/4.5.13, Apache-2.0, approved, CQ22761 | |||
maven/mavencentral/org.apache.httpcomponents/httpcore/4.4.14, Apache-2.0, approved, CQ18704 | |||
maven/mavencentral/org.apache.sshd/sshd-common/2.6.0, Apache-2.0 AND ISC, approved, CQ22992 | |||
maven/mavencentral/org.apache.sshd/sshd-core/2.6.0, Apache-2.0 AND ISC, approved, CQ22992 | |||
maven/mavencentral/org.apache.sshd/sshd-osgi/2.6.0, Apache-2.0 AND ISC, approved, CQ22992 | |||
maven/mavencentral/org.apache.sshd/sshd-sftp/2.6.0, Apache-2.0 AND ISC, approved, CQ22993 | |||
maven/mavencentral/org.assertj/assertj-core/3.14.0, Apache-2.0, approved, clearlydefined | |||
maven/mavencentral/org.bouncycastle/bcpg-jdk15on/1.65, Apache-2.0, approved, CQ21975 | |||
maven/mavencentral/org.bouncycastle/bcpkix-jdk15on/1.65, MIT AND LicenseRef-Public-Domain, approved, CQ21976 | |||
maven/mavencentral/org.bouncycastle/bcprov-jdk15on/1.65.01, MIT AND LicenseRef-Public-Domain, approved, CQ21977 | |||
maven/mavencentral/org.eclipse.jetty/jetty-http/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-io/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-security/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-server/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-servlet/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-util-ajax/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jetty/jetty-util/9.4.36.v20210114, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ant/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.archive/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.gpg.bc/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.apache/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.server/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.http.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.http/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit.ssh/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.junit/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.server/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.lfs/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.pgm/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.apache/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ssh.jsch/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.test/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit.ui/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.eclipse.jgit/org.eclipse.jgit/5.11.0-SNAPSHOT, , approved, eclipse | |||
maven/mavencentral/org.hamcrest/hamcrest-core/1.3, BSD-2-Clause, approved, CQ7063 | |||
maven/mavencentral/org.mockito/mockito-core/2.23.0, MIT, approved, CQ17976 | |||
maven/mavencentral/org.objenesis/objenesis/2.6, Apache-2.0, approved, CQ15478 | |||
maven/mavencentral/org.openjdk.jmh/jmh-core/1.21, GPL-2.0, approved, CQ20517 | |||
maven/mavencentral/org.openjdk.jmh/jmh-generator-annprocess/1.21, GPL-2.0, approved, CQ20518 | |||
maven/mavencentral/org.osgi/org.osgi.core/4.3.1, Apache-2.0, approved, CQ10111 | |||
maven/mavencentral/org.slf4j/slf4j-api/1.7.30, MIT, approved, CQ13368 | |||
maven/mavencentral/org.slf4j/slf4j-log4j12/1.7.30, MIT, approved, CQ7665 | |||
maven/mavencentral/org.tukaani/xz/1.8, LicenseRef-Public-Domain, approved, CQ15386 |
@@ -44,7 +44,9 @@ import org.eclipse.jgit.internal.storage.file.FileRepository; | |||
import org.eclipse.jgit.internal.storage.file.LockFile; | |||
import org.eclipse.jgit.internal.storage.file.ObjectDirectory; | |||
import org.eclipse.jgit.internal.storage.file.Pack; | |||
import org.eclipse.jgit.internal.storage.file.PackFile; | |||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
@@ -906,23 +908,22 @@ public class TestRepository<R extends Repository> implements AutoCloseable { | |||
ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); | |||
NullProgressMonitor m = NullProgressMonitor.INSTANCE; | |||
final File pack, idx; | |||
final PackFile pack, idx; | |||
try (PackWriter pw = new PackWriter(db)) { | |||
Set<ObjectId> all = new HashSet<>(); | |||
for (Ref r : db.getRefDatabase().getRefs()) | |||
all.add(r.getObjectId()); | |||
pw.preparePack(m, all, PackWriter.NONE); | |||
final ObjectId name = pw.computeName(); | |||
pack = nameFor(odb, name, ".pack"); | |||
pack = new PackFile(odb.getPackDirectory(), pw.computeName(), | |||
PackExt.PACK); | |||
try (OutputStream out = | |||
new BufferedOutputStream(new FileOutputStream(pack))) { | |||
pw.writePack(m, m, out); | |||
} | |||
pack.setReadOnly(); | |||
idx = nameFor(odb, name, ".idx"); | |||
idx = pack.create(PackExt.INDEX); | |||
try (OutputStream out = | |||
new BufferedOutputStream(new FileOutputStream(idx))) { | |||
pw.writeIndex(out); | |||
@@ -960,11 +961,6 @@ public class TestRepository<R extends Repository> implements AutoCloseable { | |||
} | |||
} | |||
private static File nameFor(ObjectDirectory odb, ObjectId name, String t) { | |||
File packdir = odb.getPackDirectory(); | |||
return new File(packdir, "pack-" + name.name() + t); | |||
} | |||
private void writeFile(File p, byte[] bin) throws IOException, | |||
ObjectWritingException { | |||
final LockFile lck = new LockFile(p); |
@@ -28,6 +28,7 @@ import java.util.Collection; | |||
import java.util.List; | |||
import org.eclipse.jgit.errors.AmbiguousObjectException; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
import org.eclipse.jgit.lib.AbbreviatedObjectId; | |||
@@ -144,10 +145,9 @@ public class AbbreviationTest extends LocalDiskRepositoryTestCase { | |||
objects.add(new PackedObjectInfo(ObjectId.fromRaw(idBuf))); | |||
} | |||
String packName = "pack-" + id.name(); | |||
File packDir = db.getObjectDatabase().getPackDirectory(); | |||
File idxFile = new File(packDir, packName + ".idx"); | |||
File packFile = new File(packDir, packName + ".pack"); | |||
PackFile idxFile = new PackFile(packDir, id, PackExt.INDEX); | |||
PackFile packFile = idxFile.create(PackExt.PACK); | |||
FileUtils.mkdir(packDir, true); | |||
try (OutputStream dst = new BufferedOutputStream( | |||
new FileOutputStream(idxFile))) { |
@@ -27,6 +27,7 @@ import java.time.Instant; | |||
import org.eclipse.jgit.errors.IncorrectObjectTypeException; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.junit.RepositoryTestCase; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
@@ -193,9 +194,10 @@ public class ConcurrentRepackTest extends RepositoryTestCase { | |||
pw.addObject(o); | |||
} | |||
final ObjectId name = pw.computeName(); | |||
final File packFile = fullPackFileName(name, ".pack"); | |||
final File idxFile = fullPackFileName(name, ".idx"); | |||
PackFile packFile = new PackFile( | |||
db.getObjectDatabase().getPackDirectory(), pw.computeName(), | |||
PackExt.PACK); | |||
PackFile idxFile = packFile.create(PackExt.INDEX); | |||
final File[] files = new File[] { packFile, idxFile }; | |||
write(files, pw); | |||
return files; | |||
@@ -242,11 +244,6 @@ public class ConcurrentRepackTest extends RepositoryTestCase { | |||
} | |||
} | |||
private File fullPackFileName(ObjectId name, String suffix) { | |||
final File packdir = db.getObjectDatabase().getPackDirectory(); | |||
return new File(packdir, "pack-" + name.name() + suffix); | |||
} | |||
private RevObject writeBlob(Repository repo, String data) | |||
throws IOException { | |||
final byte[] bytes = Constants.encode(data); |
@@ -23,6 +23,7 @@ import java.util.List; | |||
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; | |||
import org.eclipse.jgit.lib.ConfigConstants; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.RefUpdate; | |||
import org.eclipse.jgit.revwalk.RevCommit; | |||
import org.eclipse.jgit.storage.file.FileBasedConfig; | |||
@@ -295,7 +296,7 @@ public class GcBasicPackingTest extends GcTestCase { | |||
// pack loose object into packfile | |||
gc.setExpireAgeMillis(0); | |||
gc.gc(); | |||
File oldPackfile = tr.getRepository().getObjectDatabase().getPacks() | |||
PackFile oldPackfile = tr.getRepository().getObjectDatabase().getPacks() | |||
.iterator().next().getPackFile(); | |||
assertTrue(oldPackfile.exists()); | |||
@@ -309,12 +310,59 @@ public class GcBasicPackingTest extends GcTestCase { | |||
configureGc(gc, false).setPreserveOldPacks(true); | |||
gc.gc(); | |||
File oldPackDir = repo.getObjectDatabase().getPreservedDirectory(); | |||
String oldPackFileName = oldPackfile.getName(); | |||
String oldPackName = oldPackFileName.substring(0, | |||
oldPackFileName.lastIndexOf('.')) + ".old-pack"; //$NON-NLS-1$ | |||
File preservePackFile = new File(oldPackDir, oldPackName); | |||
assertTrue(preservePackFile.exists()); | |||
File preservedPackFile = oldPackfile.createPreservedForDirectory( | |||
repo.getObjectDatabase().getPreservedDirectory()); | |||
assertTrue(preservedPackFile.exists()); | |||
} | |||
@Test | |||
public void testPruneAndRestoreOldPacks() throws Exception { | |||
String tempRef = "refs/heads/soon-to-be-unreferenced"; | |||
BranchBuilder bb = tr.branch(tempRef); | |||
bb.commit().add("A", "A").add("B", "B").create(); | |||
// Verify setup conditions | |||
stats = gc.getStatistics(); | |||
assertEquals(4, stats.numberOfLooseObjects); | |||
assertEquals(0, stats.numberOfPackedObjects); | |||
// Force all referenced objects into packs (to avoid having loose objects) | |||
configureGc(gc, false); | |||
gc.setExpireAgeMillis(0); | |||
gc.setPackExpireAgeMillis(0); | |||
gc.gc(); | |||
stats = gc.getStatistics(); | |||
assertEquals(0, stats.numberOfLooseObjects); | |||
assertEquals(4, stats.numberOfPackedObjects); | |||
assertEquals(1, stats.numberOfPackFiles); | |||
// Delete the temp ref, orphaning its commit | |||
RefUpdate update = tr.getRepository().getRefDatabase().newUpdate(tempRef, false); | |||
update.setForceUpdate(true); | |||
ObjectId objectId = update.getOldObjectId(); // remember it so we can restore it! | |||
RefUpdate.Result result = update.delete(); | |||
assertEquals(RefUpdate.Result.FORCED, result); | |||
fsTick(); | |||
// Repack with only orphaned commit, so packfile will be pruned | |||
configureGc(gc, false).setPreserveOldPacks(true); | |||
gc.gc(); | |||
stats = gc.getStatistics(); | |||
assertEquals(0, stats.numberOfLooseObjects); | |||
assertEquals(0, stats.numberOfPackedObjects); | |||
assertEquals(0, stats.numberOfPackFiles); | |||
// Restore the temp ref to the deleted commit, should restore old-packs! | |||
update = tr.getRepository().getRefDatabase().newUpdate(tempRef, false); | |||
update.setNewObjectId(objectId); | |||
update.setExpectedOldObjectId(null); | |||
result = update.update(); | |||
assertEquals(RefUpdate.Result.NEW, result); | |||
stats = gc.getStatistics(); | |||
assertEquals(4, stats.numberOfPackedObjects); | |||
assertEquals(1, stats.numberOfPackFiles); | |||
} | |||
private PackConfig configureGc(GC myGc, boolean aggressive) { |
@@ -14,10 +14,10 @@ import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertFalse; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.File; | |||
import java.util.Iterator; | |||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.junit.TestRepository.BranchBuilder; | |||
import org.junit.Test; | |||
@@ -40,10 +40,7 @@ public class GcKeepFilesTest extends GcTestCase { | |||
.iterator(); | |||
Pack singlePack = packIt.next(); | |||
assertFalse(packIt.hasNext()); | |||
String packFileName = singlePack.getPackFile().getPath(); | |||
String keepFileName = packFileName.substring(0, | |||
packFileName.lastIndexOf('.')) + ".keep"; | |||
File keepFile = new File(keepFileName); | |||
PackFile keepFile = singlePack.getPackFile().create(PackExt.KEEP); | |||
assertFalse(keepFile.exists()); | |||
assertTrue(keepFile.createNewFile()); | |||
bb.commit().add("A", "A2").add("B", "B2").create(); |
@@ -0,0 +1,169 @@ | |||
/* | |||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* 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.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertThrows; | |||
import static org.junit.Assert.assertTrue; | |||
import java.io.File; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.junit.Test; | |||
public class PackFileTest { | |||
private static final ObjectId TEST_OID = ObjectId | |||
.fromString("0123456789012345678901234567890123456789"); | |||
private static final String TEST_ID = TEST_OID.name(); | |||
private static final String PREFIX = "pack-"; | |||
private static final String OLD_PREFIX = "old-"; | |||
private static final String OLD_PACK = PREFIX + TEST_ID + "." + OLD_PREFIX | |||
+ PackExt.PACK.getExtension(); | |||
private static final File TEST_PACK_DIR = new File( | |||
"/path/to/repo.git/objects/pack"); | |||
private static final File TEST_PRESERVED_DIR = new File(TEST_PACK_DIR, | |||
"preserved"); | |||
private static final PackFile TEST_PACKFILE_NO_EXT = new PackFile( | |||
new File(TEST_PACK_DIR, PREFIX + TEST_ID)); | |||
@Test | |||
public void objectsAreSameFromAnyConstructor() throws Exception { | |||
String name = PREFIX + TEST_ID + "." + PackExt.PACK.getExtension(); | |||
File pack = new File(TEST_PACK_DIR, name); | |||
PackFile pf = new PackFile(pack); | |||
PackFile pfFromDirAndName = new PackFile(TEST_PACK_DIR, name); | |||
assertPackFilesEqual(pf, pfFromDirAndName); | |||
PackFile pfFromOIdAndExt = new PackFile(TEST_PACK_DIR, TEST_OID, | |||
PackExt.PACK); | |||
assertPackFilesEqual(pf, pfFromOIdAndExt); | |||
PackFile pfFromIdAndExt = new PackFile(TEST_PACK_DIR, TEST_ID, | |||
PackExt.PACK); | |||
assertPackFilesEqual(pf, pfFromIdAndExt); | |||
} | |||
@Test | |||
public void idIsSameFromFileWithOrWithoutExt() throws Exception { | |||
PackFile packWithExt = new PackFile(new File(TEST_PACK_DIR, | |||
PREFIX + TEST_ID + "." + PackExt.PACK.getExtension())); | |||
assertEquals(packWithExt.getId(), TEST_PACKFILE_NO_EXT.getId()); | |||
} | |||
@Test | |||
public void idIsSameFromFileWithOrWithoutPrefix() throws Exception { | |||
PackFile packWithoutPrefix = new PackFile( | |||
new File(TEST_PACK_DIR, TEST_ID)); | |||
assertEquals(packWithoutPrefix.getId(), TEST_PACKFILE_NO_EXT.getId()); | |||
} | |||
@Test | |||
public void canCreatePreservedFromFile() throws Exception { | |||
PackFile preserved = new PackFile( | |||
new File(TEST_PRESERVED_DIR, OLD_PACK)); | |||
assertTrue(preserved.getName().contains(OLD_PACK)); | |||
assertEquals(preserved.getId(), TEST_ID); | |||
assertEquals(preserved.getPackExt(), PackExt.PACK); | |||
} | |||
@Test | |||
public void canCreatePreservedFromDirAndName() throws Exception { | |||
PackFile preserved = new PackFile(TEST_PRESERVED_DIR, OLD_PACK); | |||
assertTrue(preserved.getName().contains(OLD_PACK)); | |||
assertEquals(preserved.getId(), TEST_ID); | |||
assertEquals(preserved.getPackExt(), PackExt.PACK); | |||
} | |||
@Test | |||
public void cannotCreatePreservedNoExtFromNonPreservedNoExt() | |||
throws Exception { | |||
assertThrows(IllegalArgumentException.class, () -> TEST_PACKFILE_NO_EXT | |||
.createPreservedForDirectory(TEST_PRESERVED_DIR)); | |||
} | |||
@Test | |||
public void canCreateAnyExtFromAnyExt() throws Exception { | |||
for (PackExt from : PackExt.values()) { | |||
PackFile dotFrom = TEST_PACKFILE_NO_EXT.create(from); | |||
for (PackExt to : PackExt.values()) { | |||
PackFile dotTo = dotFrom.create(to); | |||
File expected = new File(TEST_PACK_DIR, | |||
PREFIX + TEST_ID + "." + to.getExtension()); | |||
assertEquals(dotTo.getPackExt(), to); | |||
assertEquals(dotFrom.getId(), dotTo.getId()); | |||
assertEquals(expected.getName(), dotTo.getName()); | |||
} | |||
} | |||
} | |||
@Test | |||
public void canCreatePreservedFromAnyExt() throws Exception { | |||
for (PackExt ext : PackExt.values()) { | |||
PackFile nonPreserved = TEST_PACKFILE_NO_EXT.create(ext); | |||
PackFile preserved = nonPreserved | |||
.createPreservedForDirectory(TEST_PRESERVED_DIR); | |||
File expected = new File(TEST_PRESERVED_DIR, | |||
PREFIX + TEST_ID + "." + OLD_PREFIX + ext.getExtension()); | |||
assertEquals(preserved.getName(), expected.getName()); | |||
assertEquals(preserved.getId(), TEST_ID); | |||
assertEquals(preserved.getPackExt(), nonPreserved.getPackExt()); | |||
} | |||
} | |||
@Test | |||
public void canCreateAnyPreservedExtFromAnyPreservedExt() throws Exception { | |||
// Preserved PackFiles must have an extension | |||
PackFile preserved = new PackFile(TEST_PRESERVED_DIR, OLD_PACK); | |||
for (PackExt from : PackExt.values()) { | |||
PackFile preservedWithExt = preserved.create(from); | |||
for (PackExt to : PackExt.values()) { | |||
PackFile preservedNewExt = preservedWithExt.create(to); | |||
File expected = new File(TEST_PRESERVED_DIR, PREFIX + TEST_ID | |||
+ "." + OLD_PREFIX + to.getExtension()); | |||
assertEquals(preservedNewExt.getPackExt(), to); | |||
assertEquals(preservedWithExt.getId(), preservedNewExt.getId()); | |||
assertEquals(preservedNewExt.getName(), expected.getName()); | |||
} | |||
} | |||
} | |||
@Test | |||
public void canCreateNonPreservedFromAnyPreservedExt() throws Exception { | |||
// Preserved PackFiles must have an extension | |||
PackFile preserved = new PackFile(TEST_PRESERVED_DIR, OLD_PACK); | |||
for (PackExt ext : PackExt.values()) { | |||
PackFile preservedWithExt = preserved.create(ext); | |||
PackFile nonPreserved = preservedWithExt | |||
.createForDirectory(TEST_PACK_DIR); | |||
File expected = new File(TEST_PACK_DIR, | |||
PREFIX + TEST_ID + "." + ext.getExtension()); | |||
assertEquals(nonPreserved.getName(), expected.getName()); | |||
assertEquals(nonPreserved.getId(), TEST_ID); | |||
assertEquals(nonPreserved.getPackExt(), | |||
preservedWithExt.getPackExt()); | |||
} | |||
} | |||
private void assertPackFilesEqual(PackFile p1, PackFile p2) { | |||
// for test purposes, considered equal if id, name, and ext are equal | |||
assertEquals(p1.getId(), p2.getId()); | |||
assertEquals(p1.getPackExt(), p2.getPackExt()); | |||
assertEquals(p1.getName(), p2.getName()); | |||
} | |||
} |
@@ -246,8 +246,8 @@ public class PackTest extends LocalDiskRepositoryTestCase { | |||
File dir = new File(repo.getObjectDatabase().getDirectory(), | |||
"pack"); | |||
File packName = new File(dir, idA.name() + ".pack"); | |||
File idxName = new File(dir, idA.name() + ".idx"); | |||
PackFile packName = new PackFile(dir, idA.name() + ".pack"); | |||
PackFile idxName = packName.create(PackExt.INDEX); | |||
try (FileOutputStream f = new FileOutputStream(packName)) { | |||
f.write(packContents.toByteArray()); | |||
@@ -261,7 +261,7 @@ public class PackTest extends LocalDiskRepositoryTestCase { | |||
new PackIndexWriterV1(f).write(list, footer); | |||
} | |||
Pack pack = new Pack(packName, PackExt.INDEX.getBit()); | |||
Pack pack = new Pack(packName, null); | |||
try { | |||
pack.get(wc, b); | |||
fail("expected LargeObjectException.ExceedsByteArrayLimit"); |
@@ -34,6 +34,7 @@ import java.util.Set; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.internal.storage.file.PackIndex.MutableEntry; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.junit.JGitTestUtil; | |||
import org.eclipse.jgit.junit.TestRepository; | |||
@@ -305,9 +306,9 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
@Test | |||
public void testWritePack2DeltasCRC32Copy() throws IOException { | |||
final File packDir = db.getObjectDatabase().getPackDirectory(); | |||
final File crc32Pack = new File(packDir, | |||
final PackFile crc32Pack = new PackFile(packDir, | |||
"pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack"); | |||
final File crc32Idx = new File(packDir, | |||
final PackFile crc32Idx = new PackFile(packDir, | |||
"pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx"); | |||
copyFile(JGitTestUtil.getTestResourceFile( | |||
"pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2"), | |||
@@ -471,10 +472,8 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
config.setIndexVersion(2); | |||
writeVerifyPack4(false); | |||
File packFile = pack.getPackFile(); | |||
String name = packFile.getName(); | |||
String base = name.substring(0, name.lastIndexOf('.')); | |||
File indexFile = new File(packFile.getParentFile(), base + ".idx"); | |||
PackFile packFile = pack.getPackFile(); | |||
PackFile indexFile = packFile.create(PackExt.INDEX); | |||
// Validate that IndexPack came up with the right CRC32 value. | |||
final PackIndex idx1 = PackIndex.open(indexFile); | |||
@@ -685,14 +684,14 @@ public class PackWriterTest extends SampleDataRepositoryTestCase { | |||
ObjectWalk ow = walk.toObjectWalkWithSameObjects(); | |||
pw.preparePack(NullProgressMonitor.INSTANCE, ow, want, have, NONE); | |||
String id = pw.computeName().getName(); | |||
File packdir = repo.getObjectDatabase().getPackDirectory(); | |||
File packFile = new File(packdir, "pack-" + id + ".pack"); | |||
PackFile packFile = new PackFile(packdir, pw.computeName(), | |||
PackExt.PACK); | |||
try (FileOutputStream packOS = new FileOutputStream(packFile)) { | |||
pw.writePack(NullProgressMonitor.INSTANCE, | |||
NullProgressMonitor.INSTANCE, packOS); | |||
} | |||
File idxFile = new File(packdir, "pack-" + id + ".idx"); | |||
PackFile idxFile = packFile.create(PackExt.INDEX); | |||
try (FileOutputStream idxOS = new FileOutputStream(idxFile)) { | |||
pw.writeIndex(idxOS); | |||
} |
@@ -743,6 +743,7 @@ unmergedPath=Unmerged path: {0} | |||
unmergedPaths=Repository contains unmerged paths | |||
unpackException=Exception while parsing pack stream | |||
unreadablePackIndex=Unreadable pack index: {0} | |||
unrecognizedPackExtension=Unrecognized pack extension: {0} | |||
unrecognizedRef=Unrecognized ref: {0} | |||
unsetMark=Mark not set | |||
unsupportedAlternates=Alternates not supported |
@@ -771,6 +771,7 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String unmergedPaths; | |||
/***/ public String unpackException; | |||
/***/ public String unreadablePackIndex; | |||
/***/ public String unrecognizedPackExtension; | |||
/***/ public String unrecognizedRef; | |||
/***/ public String unsetMark; | |||
/***/ public String unsupportedAlternates; |
@@ -12,6 +12,8 @@ package org.eclipse.jgit.internal.storage.file; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP; | |||
import java.io.File; | |||
import java.io.FileOutputStream; | |||
@@ -346,7 +348,7 @@ public class GC { | |||
if (shouldLoosen) { | |||
loosen(inserter, reader, oldPack, ids); | |||
} | |||
prunePack(oldName); | |||
prunePack(oldPack.getPackFile()); | |||
} | |||
} | |||
@@ -360,19 +362,17 @@ public class GC { | |||
* moves the pack file to the preserved directory | |||
* | |||
* @param packFile | |||
* @param packName | |||
* @param ext | |||
* @param deleteOptions | |||
* @throws IOException | |||
*/ | |||
private void removeOldPack(File packFile, String packName, PackExt ext, | |||
int deleteOptions) throws IOException { | |||
private void removeOldPack(PackFile packFile, int deleteOptions) | |||
throws IOException { | |||
if (pconfig.isPreserveOldPacks()) { | |||
File oldPackDir = repo.getObjectDatabase().getPreservedDirectory(); | |||
FileUtils.mkdir(oldPackDir, true); | |||
String oldPackName = "pack-" + packName + ".old-" + ext.getExtension(); //$NON-NLS-1$ //$NON-NLS-2$ | |||
File oldPackFile = new File(oldPackDir, oldPackName); | |||
PackFile oldPackFile = packFile | |||
.createPreservedForDirectory(oldPackDir); | |||
FileUtils.rename(packFile, oldPackFile); | |||
} else { | |||
FileUtils.delete(packFile, deleteOptions); | |||
@@ -401,27 +401,21 @@ public class GC { | |||
* ".index" file and when failing to delete the ".pack" file we are left | |||
* with a ".pack" file without a ".index" file. | |||
* | |||
* @param packName | |||
* @param packFile | |||
*/ | |||
private void prunePack(String packName) { | |||
PackExt[] extensions = PackExt.values(); | |||
private void prunePack(PackFile packFile) { | |||
try { | |||
// Delete the .pack file first and if this fails give up on deleting | |||
// the other files | |||
int deleteOptions = FileUtils.RETRY | FileUtils.SKIP_MISSING; | |||
for (PackExt ext : extensions) | |||
if (PackExt.PACK.equals(ext)) { | |||
File f = nameFor(packName, "." + ext.getExtension()); //$NON-NLS-1$ | |||
removeOldPack(f, packName, ext, deleteOptions); | |||
break; | |||
} | |||
removeOldPack(packFile.create(PackExt.PACK), deleteOptions); | |||
// The .pack file has been deleted. Delete as many as the other | |||
// files as you can. | |||
deleteOptions |= FileUtils.IGNORE_ERRORS; | |||
for (PackExt ext : extensions) { | |||
for (PackExt ext : PackExt.values()) { | |||
if (!PackExt.PACK.equals(ext)) { | |||
File f = nameFor(packName, "." + ext.getExtension()); //$NON-NLS-1$ | |||
removeOldPack(f, packName, ext, deleteOptions); | |||
removeOldPack(packFile.create(ext), deleteOptions); | |||
} | |||
} | |||
} catch (IOException e) { | |||
@@ -973,20 +967,21 @@ public class GC { | |||
return; | |||
} | |||
String base = null; | |||
String latestId = null; | |||
for (String n : fileNames) { | |||
if (n.endsWith(PACK_EXT) || n.endsWith(KEEP_EXT)) { | |||
base = n.substring(0, n.lastIndexOf('.')); | |||
} else { | |||
if (base == null || !n.startsWith(base)) { | |||
try { | |||
Path delete = packDir.resolve(n); | |||
FileUtils.delete(delete.toFile(), | |||
FileUtils.RETRY | FileUtils.SKIP_MISSING); | |||
LOG.warn(JGitText.get().deletedOrphanInPackDir, delete); | |||
} catch (IOException e) { | |||
LOG.error(e.getMessage(), e); | |||
} | |||
PackFile pf = new PackFile(packDir.toFile(), n); | |||
PackExt ext = pf.getPackExt(); | |||
if (ext.equals(PACK) || ext.equals(KEEP)) { | |||
latestId = pf.getId(); | |||
} | |||
if (latestId == null || !pf.getId().equals(latestId)) { | |||
// no pack or keep for this id | |||
try { | |||
FileUtils.delete(pf, | |||
FileUtils.RETRY | FileUtils.SKIP_MISSING); | |||
LOG.warn(JGitText.get().deletedOrphanInPackDir, pf); | |||
} catch (IOException e) { | |||
LOG.error(e.getMessage(), e); | |||
} | |||
} | |||
} | |||
@@ -1168,7 +1163,7 @@ public class GC { | |||
checkCancelled(); | |||
// create temporary files | |||
String id = pw.computeName().getName(); | |||
ObjectId id = pw.computeName(); | |||
File packdir = repo.getObjectDatabase().getPackDirectory(); | |||
packdir.mkdirs(); | |||
tmpPack = File.createTempFile("gc_", ".pack_tmp", packdir); //$NON-NLS-1$ //$NON-NLS-2$ | |||
@@ -1218,7 +1213,8 @@ public class GC { | |||
} | |||
// rename the temporary files to real files | |||
File realPack = nameFor(id, ".pack"); //$NON-NLS-1$ | |||
File packDir = repo.getObjectDatabase().getPackDirectory(); | |||
PackFile realPack = new PackFile(packDir, id, PackExt.PACK); | |||
repo.getObjectDatabase().closeAllPackHandles(realPack); | |||
tmpPack.setReadOnly(); | |||
@@ -1228,8 +1224,7 @@ public class GC { | |||
File tmpExt = tmpEntry.getValue(); | |||
tmpExt.setReadOnly(); | |||
File realExt = nameFor(id, | |||
"." + tmpEntry.getKey().getExtension()); //$NON-NLS-1$ | |||
PackFile realExt = new PackFile(packDir, id, tmpEntry.getKey()); | |||
try { | |||
FileUtils.rename(tmpExt, realExt, | |||
StandardCopyOption.ATOMIC_MOVE); | |||
@@ -1275,11 +1270,6 @@ public class GC { | |||
} | |||
} | |||
private File nameFor(String name, String ext) { | |||
File packdir = repo.getObjectDatabase().getPackDirectory(); | |||
return new File(packdir, "pack-" + name + ext); //$NON-NLS-1$ | |||
} | |||
private void checkCancelled() throws CancelledException { | |||
if (pm.isCancelled() || Thread.currentThread().isInterrupted()) { | |||
throw new CancelledException(JGitText.get().operationCanceled); |
@@ -17,6 +17,7 @@ import java.util.List; | |||
import org.eclipse.jgit.internal.storage.pack.CachedPack; | |||
import org.eclipse.jgit.internal.storage.pack.ObjectToPack; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackOutputStream; | |||
import org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation; | |||
@@ -88,6 +89,6 @@ class LocalCachedPack extends CachedPack { | |||
private String getPackFilePath(String packName) { | |||
final File packDir = odb.getPackDirectory(); | |||
return new File(packDir, "pack-" + packName + ".pack").getPath(); //$NON-NLS-1$ //$NON-NLS-2$ | |||
return new PackFile(packDir, packName, PackExt.PACK).getPath(); | |||
} | |||
} |
@@ -11,8 +11,9 @@ | |||
package org.eclipse.jgit.internal.storage.file; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; | |||
import java.io.BufferedReader; | |||
import java.io.File; | |||
@@ -79,7 +80,7 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
private final PackDirectory packed; | |||
private final File preservedDirectory; | |||
private final PackDirectory preserved; | |||
private final File alternatesFile; | |||
@@ -117,10 +118,11 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
objects = dir; | |||
infoDirectory = new File(objects, "info"); //$NON-NLS-1$ | |||
File packDirectory = new File(objects, "pack"); //$NON-NLS-1$ | |||
preservedDirectory = new File(packDirectory, "preserved"); //$NON-NLS-1$ | |||
File preservedDirectory = new File(packDirectory, "preserved"); //$NON-NLS-1$ | |||
alternatesFile = new File(objects, Constants.INFO_ALTERNATES); | |||
loose = new LooseObjects(objects); | |||
packed = new PackDirectory(config, packDirectory); | |||
preserved = new PackDirectory(config, preservedDirectory); | |||
this.fs = fs; | |||
this.shallowFile = shallowFile; | |||
@@ -156,7 +158,7 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
* @return the location of the <code>preserved</code> directory. | |||
*/ | |||
public final File getPreservedDirectory() { | |||
return preservedDirectory; | |||
return preserved.getDirectory(); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -216,26 +218,26 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
* Add a single existing pack to the list of available pack files. | |||
*/ | |||
@Override | |||
public Pack openPack(File pack) | |||
throws IOException { | |||
final String p = pack.getName(); | |||
if (p.length() != 50 || !p.startsWith("pack-") || !p.endsWith(".pack")) //$NON-NLS-1$ //$NON-NLS-2$ | |||
throw new IOException(MessageFormat.format(JGitText.get().notAValidPack, pack)); | |||
// The pack and index are assumed to exist. The existence of other | |||
// extensions needs to be explicitly checked. | |||
// | |||
int extensions = PACK.getBit() | INDEX.getBit(); | |||
final String base = p.substring(0, p.length() - 4); | |||
for (PackExt ext : PackExt.values()) { | |||
if ((extensions & ext.getBit()) == 0) { | |||
final String name = base + ext.getExtension(); | |||
if (new File(pack.getParentFile(), name).exists()) | |||
extensions |= ext.getBit(); | |||
} | |||
} | |||
Pack res = new Pack(pack, extensions); | |||
public Pack openPack(File pack) throws IOException { | |||
PackFile pf; | |||
try { | |||
pf = new PackFile(pack); | |||
} catch (IllegalArgumentException e) { | |||
throw new IOException( | |||
MessageFormat.format(JGitText.get().notAValidPack, pack), | |||
e); | |||
} | |||
String p = pf.getName(); | |||
// TODO(nasserg): See if PackFile can do these checks instead | |||
if (p.length() != 50 || !p.startsWith("pack-") //$NON-NLS-1$ | |||
|| !pf.getPackExt().equals(PACK)) { | |||
throw new IOException( | |||
MessageFormat.format(JGitText.get().notAValidPack, pack)); | |||
} | |||
PackFile bitmapIdx = pf.create(BITMAP_INDEX); | |||
Pack res = new Pack(pack, bitmapIdx.exists() ? bitmapIdx : null); | |||
packed.insert(res); | |||
return res; | |||
} | |||
@@ -250,7 +252,13 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
@Override | |||
public boolean has(AnyObjectId objectId) { | |||
return loose.hasCached(objectId) | |||
|| hasPackedInSelfOrAlternate(objectId, null) | |||
|| hasPackedOrLooseInSelfOrAlternate(objectId) | |||
|| (restoreFromSelfOrAlternate(objectId, null) | |||
&& hasPackedOrLooseInSelfOrAlternate(objectId)); | |||
} | |||
private boolean hasPackedOrLooseInSelfOrAlternate(AnyObjectId objectId) { | |||
return hasPackedInSelfOrAlternate(objectId, null) | |||
|| hasLooseInSelfOrAlternate(objectId, null); | |||
} | |||
@@ -319,6 +327,15 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
@Override | |||
ObjectLoader openObject(WindowCursor curs, AnyObjectId objectId) | |||
throws IOException { | |||
ObjectLoader ldr = openObjectWithoutRestoring(curs, objectId); | |||
if (ldr == null && restoreFromSelfOrAlternate(objectId, null)) { | |||
ldr = openObjectWithoutRestoring(curs, objectId); | |||
} | |||
return ldr; | |||
} | |||
private ObjectLoader openObjectWithoutRestoring(WindowCursor curs, AnyObjectId objectId) | |||
throws IOException { | |||
if (loose.hasCached(objectId)) { | |||
ObjectLoader ldr = openLooseObject(curs, objectId); | |||
if (ldr != null) { | |||
@@ -380,8 +397,16 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
} | |||
@Override | |||
long getObjectSize(WindowCursor curs, AnyObjectId id) | |||
throws IOException { | |||
long getObjectSize(WindowCursor curs, AnyObjectId id) throws IOException { | |||
long sz = getObjectSizeWithoutRestoring(curs, id); | |||
if (0 > sz && restoreFromSelfOrAlternate(id, null)) { | |||
sz = getObjectSizeWithoutRestoring(curs, id); | |||
} | |||
return sz; | |||
} | |||
private long getObjectSizeWithoutRestoring(WindowCursor curs, | |||
AnyObjectId id) throws IOException { | |||
if (loose.hasCached(id)) { | |||
long len = loose.getSize(curs, id); | |||
if (0 <= len) { | |||
@@ -449,6 +474,51 @@ public class ObjectDirectory extends FileObjectDatabase { | |||
} | |||
} | |||
private boolean restoreFromSelfOrAlternate(AnyObjectId objectId, | |||
Set<AlternateHandle.Id> skips) { | |||
if (restoreFromSelf(objectId)) { | |||
return true; | |||
} | |||
skips = addMe(skips); | |||
for (AlternateHandle alt : myAlternates()) { | |||
if (!skips.contains(alt.getId())) { | |||
if (alt.db.restoreFromSelfOrAlternate(objectId, skips)) { | |||
return true; | |||
} | |||
} | |||
} | |||
return false; | |||
} | |||
private boolean restoreFromSelf(AnyObjectId objectId) { | |||
Pack preservedPack = preserved.getPack(objectId); | |||
if (preservedPack == null) { | |||
return false; | |||
} | |||
PackFile preservedFile = new PackFile(preservedPack.getPackFile()); | |||
// Restore the index last since the set will be considered for use once | |||
// the index appears. | |||
for (PackExt ext : PackExt.values()) { | |||
if (!INDEX.equals(ext)) { | |||
restore(preservedFile.create(ext)); | |||
} | |||
} | |||
restore(preservedFile.create(INDEX)); | |||
return true; | |||
} | |||
private boolean restore(PackFile preservedPack) { | |||
PackFile restored = preservedPack | |||
.createForDirectory(packed.getDirectory()); | |||
try { | |||
Files.createLink(restored.toPath(), preservedPack.toPath()); | |||
} catch (IOException e) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
@Override | |||
InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id, | |||
boolean createDuplicate) throws IOException { |
@@ -27,6 +27,7 @@ import java.util.zip.Deflater; | |||
import org.eclipse.jgit.errors.LockFailedException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.CoreConfig; | |||
@@ -426,10 +427,10 @@ public class ObjectDirectoryPackParser extends PackParser { | |||
d.update(oeBytes); | |||
} | |||
final String name = ObjectId.fromRaw(d.digest()).name(); | |||
final File packDir = new File(db.getDirectory(), "pack"); //$NON-NLS-1$ | |||
final File finalPack = new File(packDir, "pack-" + name + ".pack"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
final File finalIdx = new File(packDir, "pack-" + name + ".idx"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
ObjectId id = ObjectId.fromRaw(d.digest()); | |||
File packDir = new File(db.getDirectory(), "pack"); //$NON-NLS-1$ | |||
PackFile finalPack = new PackFile(packDir, id, PackExt.PACK); | |||
PackFile finalIdx = finalPack.create(PackExt.INDEX); | |||
final PackLock keep = new PackLock(finalPack, db.getFS()); | |||
if (!packDir.exists() && !packDir.mkdir() && !packDir.exists()) { |
@@ -12,7 +12,6 @@ | |||
package org.eclipse.jgit.internal.storage.file; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP; | |||
@@ -38,6 +37,7 @@ import java.util.zip.CRC32; | |||
import java.util.zip.DataFormatException; | |||
import java.util.zip.Inflater; | |||
import org.eclipse.jgit.annotations.Nullable; | |||
import org.eclipse.jgit.errors.CorruptObjectException; | |||
import org.eclipse.jgit.errors.LargeObjectException; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
@@ -51,7 +51,6 @@ import org.eclipse.jgit.errors.UnsupportedPackVersionException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.pack.BinaryDelta; | |||
import org.eclipse.jgit.internal.storage.pack.ObjectToPack; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackOutputStream; | |||
import org.eclipse.jgit.lib.AbbreviatedObjectId; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
@@ -78,13 +77,9 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
public static final Comparator<Pack> SORT = (a, b) -> b.packLastModified | |||
.compareTo(a.packLastModified); | |||
private final File packFile; | |||
private final PackFile packFile; | |||
private final int extensions; | |||
private File keepFile; | |||
private volatile String packName; | |||
private PackFile keepFile; | |||
final int hash; | |||
@@ -107,7 +102,8 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
private volatile Exception invalidatingCause; | |||
private boolean invalidBitmap; | |||
@Nullable | |||
private PackFile bitmapIdxFile; | |||
private AtomicInteger transientErrorCount = new AtomicInteger(); | |||
@@ -133,14 +129,14 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
* | |||
* @param packFile | |||
* path of the <code>.pack</code> file holding the data. | |||
* @param extensions | |||
* additional pack file extensions with the same base as the pack | |||
* @param bitmapIdxFile | |||
* existing bitmap index file with the same base as the pack | |||
*/ | |||
public Pack(File packFile, int extensions) { | |||
this.packFile = packFile; | |||
public Pack(File packFile, @Nullable PackFile bitmapIdxFile) { | |||
this.packFile = new PackFile(packFile); | |||
this.fileSnapshot = PackFileSnapshot.save(packFile); | |||
this.packLastModified = fileSnapshot.lastModifiedInstant(); | |||
this.extensions = extensions; | |||
this.bitmapIdxFile = bitmapIdxFile; | |||
// Multiply by 31 here so we can more directly combine with another | |||
// value in WindowCache.hash(), without doing the multiply there. | |||
@@ -156,16 +152,18 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
idx = loadedIdx; | |||
if (idx == null) { | |||
if (invalid) { | |||
throw new PackInvalidException(packFile, invalidatingCause); | |||
throw new PackInvalidException(packFile, | |||
invalidatingCause); | |||
} | |||
try { | |||
long start = System.currentTimeMillis(); | |||
idx = PackIndex.open(extFile(INDEX)); | |||
PackFile idxFile = packFile.create(INDEX); | |||
idx = PackIndex.open(idxFile); | |||
if (LOG.isDebugEnabled()) { | |||
LOG.debug(String.format( | |||
"Opening pack index %s, size %.3f MB took %d ms", //$NON-NLS-1$ | |||
extFile(INDEX).getAbsolutePath(), | |||
Float.valueOf(extFile(INDEX).length() | |||
idxFile.getAbsolutePath(), | |||
Float.valueOf(idxFile.length() | |||
/ (1024f * 1024)), | |||
Long.valueOf(System.currentTimeMillis() | |||
- start))); | |||
@@ -205,7 +203,7 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
* | |||
* @return the File object which locates this pack on disk. | |||
*/ | |||
public File getPackFile() { | |||
public PackFile getPackFile() { | |||
return packFile; | |||
} | |||
@@ -225,16 +223,7 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
* @return name extracted from {@code pack-*.pack} pattern. | |||
*/ | |||
public String getPackName() { | |||
String name = packName; | |||
if (name == null) { | |||
name = getPackFile().getName(); | |||
if (name.startsWith("pack-")) //$NON-NLS-1$ | |||
name = name.substring("pack-".length()); //$NON-NLS-1$ | |||
if (name.endsWith(".pack")) //$NON-NLS-1$ | |||
name = name.substring(0, name.length() - ".pack".length()); //$NON-NLS-1$ | |||
packName = name; | |||
} | |||
return name; | |||
return packFile.getId(); | |||
} | |||
/** | |||
@@ -261,8 +250,9 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
* @return true if a .keep file exist. | |||
*/ | |||
public boolean shouldBeKept() { | |||
if (keepFile == null) | |||
keepFile = extFile(KEEP); | |||
if (keepFile == null) { | |||
keepFile = packFile.create(KEEP); | |||
} | |||
return keepFile.exists(); | |||
} | |||
@@ -1132,26 +1122,28 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
} | |||
synchronized PackBitmapIndex getBitmapIndex() throws IOException { | |||
if (invalid || invalidBitmap) | |||
if (invalid || bitmapIdxFile == null) { | |||
return null; | |||
if (bitmapIdx == null && hasExt(BITMAP_INDEX)) { | |||
} | |||
if (bitmapIdx == null) { | |||
final PackBitmapIndex idx; | |||
try { | |||
idx = PackBitmapIndex.open(extFile(BITMAP_INDEX), idx(), | |||
idx = PackBitmapIndex.open(bitmapIdxFile, idx(), | |||
getReverseIdx()); | |||
} catch (FileNotFoundException e) { | |||
// Once upon a time this bitmap file existed. Now it | |||
// has been removed. Most likely an external gc has | |||
// removed this packfile and the bitmap | |||
invalidBitmap = true; | |||
return null; | |||
bitmapIdxFile = null; | |||
return null; | |||
} | |||
// At this point, idx() will have set packChecksum. | |||
if (Arrays.equals(packChecksum, idx.packChecksum)) | |||
if (Arrays.equals(packChecksum, idx.packChecksum)) { | |||
bitmapIdx = idx; | |||
else | |||
invalidBitmap = true; | |||
} else { | |||
bitmapIdxFile = null; | |||
} | |||
} | |||
return bitmapIdx; | |||
} | |||
@@ -1187,17 +1179,6 @@ public class Pack implements Iterable<PackIndex.MutableEntry> { | |||
} | |||
} | |||
private File extFile(PackExt ext) { | |||
String p = packFile.getName(); | |||
int dot = p.lastIndexOf('.'); | |||
String b = (dot < 0) ? p : p.substring(0, dot); | |||
return new File(packFile.getParentFile(), b + '.' + ext.getExtension()); | |||
} | |||
private boolean hasExt(PackExt ext) { | |||
return (extensions & ext.getBit()) != 0; | |||
} | |||
@SuppressWarnings("nls") | |||
@Override | |||
public String toString() { |
@@ -10,6 +10,8 @@ | |||
package org.eclipse.jgit.internal.storage.file; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; | |||
import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; | |||
import java.io.File; | |||
@@ -20,13 +22,14 @@ import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.EnumMap; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.concurrent.atomic.AtomicReference; | |||
import org.eclipse.jgit.annotations.Nullable; | |||
import org.eclipse.jgit.errors.CorruptObjectException; | |||
import org.eclipse.jgit.errors.PackInvalidException; | |||
import org.eclipse.jgit.errors.PackMismatchException; | |||
@@ -121,21 +124,36 @@ class PackDirectory { | |||
* | |||
* @param objectId | |||
* identity of the object to test for existence of. | |||
* @return true if the specified object is stored in this PackDirectory. | |||
* @return {@code true} if the specified object is stored in this PackDirectory. | |||
*/ | |||
boolean has(AnyObjectId objectId) { | |||
return getPack(objectId) != null; | |||
} | |||
/** | |||
* Get the {@link org.eclipse.jgit.internal.storage.file.Pack} for the | |||
* specified object if it is stored in this PackDirectory. | |||
* | |||
* @param objectId | |||
* identity of the object to find the Pack for. | |||
* @return {@link org.eclipse.jgit.internal.storage.file.Pack} which | |||
* contains the specified object or {@code null} if it is not stored | |||
* in this PackDirectory. | |||
*/ | |||
@Nullable | |||
Pack getPack(AnyObjectId objectId) { | |||
PackList pList; | |||
do { | |||
pList = packList.get(); | |||
for (Pack p : pList.packs) { | |||
try { | |||
if (p.hasObject(objectId)) { | |||
return true; | |||
return p; | |||
} | |||
} catch (IOException e) { | |||
// The hasObject call should have only touched the index, | |||
// so any failure here indicates the index is unreadable | |||
// by this process, and the pack is likewise not readable. | |||
// The hasObject call should have only touched the index, so | |||
// any failure here indicates the index is unreadable by | |||
// this process, and the pack is likewise not readable. | |||
LOG.warn(MessageFormat.format( | |||
JGitText.get().unableToReadPackfile, | |||
p.getPackFile().getAbsolutePath()), e); | |||
@@ -143,7 +161,7 @@ class PackDirectory { | |||
} | |||
} | |||
} while (searchPacksAgain(pList)); | |||
return false; | |||
return null; | |||
} | |||
/** | |||
@@ -398,43 +416,29 @@ class PackDirectory { | |||
private PackList scanPacksImpl(PackList old) { | |||
final Map<String, Pack> forReuse = reuseMap(old); | |||
final FileSnapshot snapshot = FileSnapshot.save(directory); | |||
final Set<String> names = listPackDirectory(); | |||
final List<Pack> list = new ArrayList<>(names.size() >> 2); | |||
Map<String, Map<PackExt, PackFile>> packFilesByExtById = getPackFilesByExtById(); | |||
List<Pack> list = new ArrayList<>(packFilesByExtById.size()); | |||
boolean foundNew = false; | |||
for (String indexName : names) { | |||
// Must match "pack-[0-9a-f]{40}.idx" to be an index. | |||
// | |||
if (indexName.length() != 49 || !indexName.endsWith(".idx")) { //$NON-NLS-1$ | |||
continue; | |||
} | |||
final String base = indexName.substring(0, indexName.length() - 3); | |||
int extensions = 0; | |||
for (PackExt ext : PackExt.values()) { | |||
if (names.contains(base + ext.getExtension())) { | |||
extensions |= ext.getBit(); | |||
} | |||
} | |||
if ((extensions & PACK.getBit()) == 0) { | |||
for (Map<PackExt, PackFile> packFilesByExt : packFilesByExtById | |||
.values()) { | |||
PackFile packFile = packFilesByExt.get(PACK); | |||
if (packFile == null || !packFilesByExt.containsKey(INDEX)) { | |||
// Sometimes C Git's HTTP fetch transport leaves a | |||
// .idx file behind and does not download the .pack. | |||
// We have to skip over such useless indexes. | |||
// | |||
// Also skip if we don't have any index for this id | |||
continue; | |||
} | |||
final String packName = base + PACK.getExtension(); | |||
final File packFile = new File(directory, packName); | |||
final Pack oldPack = forReuse.get(packName); | |||
Pack oldPack = forReuse.get(packFile.getName()); | |||
if (oldPack != null | |||
&& !oldPack.getFileSnapshot().isModified(packFile)) { | |||
forReuse.remove(packName); | |||
forReuse.remove(packFile.getName()); | |||
list.add(oldPack); | |||
continue; | |||
} | |||
list.add(new Pack(packFile, extensions)); | |||
list.add(new Pack(packFile, packFilesByExt.get(BITMAP_INDEX))); | |||
foundNew = true; | |||
} | |||
@@ -487,18 +491,42 @@ class PackDirectory { | |||
return forReuse; | |||
} | |||
private Set<String> listPackDirectory() { | |||
/** | |||
* Scans the pack directory for | |||
* {@link org.eclipse.jgit.internal.storage.file.PackFile}s and returns them | |||
* organized by their extensions and their pack ids | |||
* | |||
* Skips files in the directory that we cannot create a | |||
* {@link org.eclipse.jgit.internal.storage.file.PackFile} for. | |||
* | |||
* @return a map of {@link org.eclipse.jgit.internal.storage.file.PackFile}s | |||
* and {@link org.eclipse.jgit.internal.storage.pack.PackExt}s keyed | |||
* by pack ids | |||
*/ | |||
private Map<String, Map<PackExt, PackFile>> getPackFilesByExtById() { | |||
final String[] nameList = directory.list(); | |||
if (nameList == null) { | |||
return Collections.emptySet(); | |||
return Collections.emptyMap(); | |||
} | |||
final Set<String> nameSet = new HashSet<>(nameList.length << 1); | |||
Map<String, Map<PackExt, PackFile>> packFilesByExtById = new HashMap<>( | |||
nameList.length / 2); // assume roughly 2 files per id | |||
for (String name : nameList) { | |||
if (name.startsWith("pack-")) { //$NON-NLS-1$ | |||
nameSet.add(name); | |||
try { | |||
PackFile pack = new PackFile(directory, name); | |||
if (pack.getPackExt() != null) { | |||
Map<PackExt, PackFile> packByExt = packFilesByExtById | |||
.get(pack.getId()); | |||
if (packByExt == null) { | |||
packByExt = new EnumMap<>(PackExt.class); | |||
packFilesByExtById.put(pack.getId(), packByExt); | |||
} | |||
packByExt.put(pack.getPackExt(), pack); | |||
} | |||
} catch (IllegalArgumentException e) { | |||
continue; | |||
} | |||
} | |||
return nameSet; | |||
return packFilesByExtById; | |||
} | |||
static final class PackList { |
@@ -0,0 +1,187 @@ | |||
/* | |||
* Copyright (c) 2021 Qualcomm Innovation Center, Inc. | |||
* and other copyright owners as documented in the project's IP log. | |||
* | |||
* 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 java.io.File; | |||
import java.text.MessageFormat; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
/** | |||
* A pack file (or pack related) File. | |||
* | |||
* Example: "pack-0123456789012345678901234567890123456789.idx" | |||
*/ | |||
public class PackFile extends File { | |||
private static final long serialVersionUID = 1L; | |||
private static final String PREFIX = "pack-"; //$NON-NLS-1$ | |||
private final String base; // PREFIX + id i.e. | |||
// pack-0123456789012345678901234567890123456789 | |||
private final String id; // i.e. 0123456789012345678901234567890123456789 | |||
private final boolean hasOldPrefix; | |||
private final PackExt packExt; | |||
private static String createName(String id, PackExt extension) { | |||
return PREFIX + id + '.' + extension.getExtension(); | |||
} | |||
/** | |||
* Create a PackFile for a pack or related file. | |||
* | |||
* @param file | |||
* File pointing to the location of the file. | |||
*/ | |||
public PackFile(File file) { | |||
this(file.getParentFile(), file.getName()); | |||
} | |||
/** | |||
* Create a PackFile for a pack or related file. | |||
* | |||
* @param directory | |||
* Directory to create the PackFile in. | |||
* @param id | |||
* the {@link ObjectId} for this pack | |||
* @param ext | |||
* the <code>packExt</code> of the name. | |||
*/ | |||
public PackFile(File directory, ObjectId id, PackExt ext) { | |||
this(directory, id.name(), ext); | |||
} | |||
/** | |||
* Create a PackFile for a pack or related file. | |||
* | |||
* @param directory | |||
* Directory to create the PackFile in. | |||
* @param id | |||
* the <code>id</code> (40 Hex char) section of the pack name. | |||
* @param ext | |||
* the <code>packExt</code> of the name. | |||
*/ | |||
public PackFile(File directory, String id, PackExt ext) { | |||
this(directory, createName(id, ext)); | |||
} | |||
/** | |||
* Create a PackFile for a pack or related file. | |||
* | |||
* @param directory | |||
* Directory to create the PackFile in. | |||
* @param name | |||
* Filename (last path section) of the PackFile | |||
*/ | |||
public PackFile(File directory, String name) { | |||
super(directory, name); | |||
int dot = name.lastIndexOf('.'); | |||
if (dot < 0) { | |||
base = name; | |||
hasOldPrefix = false; | |||
packExt = null; | |||
} else { | |||
base = name.substring(0, dot); | |||
String tail = name.substring(dot + 1); // ["old-"] + extension | |||
packExt = getPackExt(tail); | |||
String old = tail.substring(0, | |||
tail.length() - getExtension().length()); | |||
hasOldPrefix = old.equals(getExtPrefix(true)); | |||
} | |||
id = base.startsWith(PREFIX) ? base.substring(PREFIX.length()) : base; | |||
} | |||
/** | |||
* Getter for the field <code>id</code>. | |||
* | |||
* @return the <code>id</code> (40 Hex char) section of the name. | |||
*/ | |||
public String getId() { | |||
return id; | |||
} | |||
/** | |||
* Getter for the field <code>packExt</code>. | |||
* | |||
* @return the <code>packExt</code> of the name. | |||
*/ | |||
public PackExt getPackExt() { | |||
return packExt; | |||
} | |||
/** | |||
* Create a new similar PackFile with the given extension instead. | |||
* | |||
* @param ext | |||
* PackExt the extension to use. | |||
* @return a PackFile instance with specified extension | |||
*/ | |||
public PackFile create(PackExt ext) { | |||
return new PackFile(getParentFile(), getName(ext)); | |||
} | |||
/** | |||
* Create a new similar PackFile in the given directory. | |||
* | |||
* @param directory | |||
* Directory to create the new PackFile in. | |||
* @return a PackFile in the given directory | |||
*/ | |||
public PackFile createForDirectory(File directory) { | |||
return new PackFile(directory, getName(false)); | |||
} | |||
/** | |||
* Create a new similar preserved PackFile in the given directory. | |||
* | |||
* @param directory | |||
* Directory to create the new PackFile in. | |||
* @return a PackFile in the given directory with "old-" prefixing the | |||
* extension | |||
*/ | |||
public PackFile createPreservedForDirectory(File directory) { | |||
return new PackFile(directory, getName(true)); | |||
} | |||
private String getName(PackExt ext) { | |||
return base + '.' + getExtPrefix(hasOldPrefix) + ext.getExtension(); | |||
} | |||
private String getName(boolean isPreserved) { | |||
return base + '.' + getExtPrefix(isPreserved) + getExtension(); | |||
} | |||
private String getExtension() { | |||
return packExt == null ? "" : packExt.getExtension(); //$NON-NLS-1$ | |||
} | |||
private static String getExtPrefix(boolean isPreserved) { | |||
return isPreserved ? "old-" : ""; //$NON-NLS-1$ //$NON-NLS-2$ | |||
} | |||
private static PackExt getPackExt(String endsWithExtension) { | |||
for (PackExt ext : PackExt.values()) { | |||
if (endsWithExtension.endsWith(ext.getExtension())) { | |||
return ext; | |||
} | |||
} | |||
throw new IllegalArgumentException(MessageFormat.format( | |||
JGitText.get().unrecognizedPackExtension, endsWithExtension)); | |||
} | |||
} |
@@ -76,6 +76,7 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; | |||
import org.eclipse.jgit.errors.LargeObjectException; | |||
import org.eclipse.jgit.errors.MissingObjectException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.lib.AbbreviatedObjectId; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
@@ -273,16 +274,16 @@ public class PackInserter extends ObjectInserter { | |||
} | |||
Collections.sort(objectList); | |||
File tmpIdx = idxFor(tmpPack); | |||
File tmpIdx = idxFor(tmpPack); // TODO(nasserg) Use PackFile? | |||
writePackIndex(tmpIdx, packHash, objectList); | |||
File realPack = new File(db.getPackDirectory(), | |||
"pack-" + computeName(objectList).name() + ".pack"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
PackFile realPack = new PackFile(db.getPackDirectory(), | |||
computeName(objectList), PackExt.PACK); | |||
db.closeAllPackHandles(realPack); | |||
tmpPack.setReadOnly(); | |||
FileUtils.rename(tmpPack, realPack, ATOMIC_MOVE); | |||
File realIdx = idxFor(realPack); | |||
PackFile realIdx = realPack.create(PackExt.INDEX); | |||
tmpIdx.setReadOnly(); | |||
try { | |||
FileUtils.rename(tmpIdx, realIdx, ATOMIC_MOVE); |
@@ -13,66 +13,26 @@ package org.eclipse.jgit.internal.storage.pack; | |||
/** | |||
* A pack file extension. | |||
*/ | |||
public class PackExt { | |||
private static volatile PackExt[] VALUES = new PackExt[] {}; | |||
public enum PackExt { | |||
/** A pack file extension. */ | |||
public static final PackExt PACK = newPackExt("pack"); //$NON-NLS-1$ | |||
PACK("pack"), //$NON-NLS-1$ | |||
/** A pack index file extension. */ | |||
public static final PackExt INDEX = newPackExt("idx"); //$NON-NLS-1$ | |||
INDEX("idx"), //$NON-NLS-1$ | |||
/** A keep pack file extension. */ | |||
public static final PackExt KEEP = newPackExt("keep"); //$NON-NLS-1$ | |||
KEEP("keep"), //$NON-NLS-1$ | |||
/** A pack bitmap index file extension. */ | |||
public static final PackExt BITMAP_INDEX = newPackExt("bitmap"); //$NON-NLS-1$ | |||
BITMAP_INDEX("bitmap"), //$NON-NLS-1$ | |||
/** A reftable file. */ | |||
public static final PackExt REFTABLE = newPackExt("ref"); //$NON-NLS-1$ | |||
/** | |||
* Get all of the PackExt values. | |||
* | |||
* @return all of the PackExt values. | |||
*/ | |||
public static PackExt[] values() { | |||
return VALUES; | |||
} | |||
/** | |||
* Returns a PackExt for the file extension and registers it in the values | |||
* array. | |||
* | |||
* @param ext | |||
* the file extension. | |||
* @return the PackExt for the ext | |||
*/ | |||
public static synchronized PackExt newPackExt(String ext) { | |||
PackExt[] dst = new PackExt[VALUES.length + 1]; | |||
for (int i = 0; i < VALUES.length; i++) { | |||
PackExt packExt = VALUES[i]; | |||
if (packExt.getExtension().equals(ext)) | |||
return packExt; | |||
dst[i] = packExt; | |||
} | |||
if (VALUES.length >= 32) | |||
throw new IllegalStateException( | |||
"maximum number of pack extensions exceeded"); //$NON-NLS-1$ | |||
PackExt value = new PackExt(ext, VALUES.length); | |||
dst[VALUES.length] = value; | |||
VALUES = dst; | |||
return value; | |||
} | |||
REFTABLE("ref"); //$NON-NLS-1$ | |||
private final String ext; | |||
private final int pos; | |||
private PackExt(String ext, int pos) { | |||
private PackExt(String ext) { | |||
this.ext = ext; | |||
this.pos = pos; | |||
} | |||
/** | |||
@@ -85,12 +45,12 @@ public class PackExt { | |||
} | |||
/** | |||
* Get the position of the extension in the values array. | |||
* Get the position of the extension in the enum declaration. | |||
* | |||
* @return the position of the extension in the values array. | |||
* @return the position of the extension in the enum declaration. | |||
*/ | |||
public int getPosition() { | |||
return pos; | |||
return ordinal(); | |||
} | |||
/** |
@@ -13,6 +13,7 @@ package org.eclipse.jgit.transport; | |||
import static org.eclipse.jgit.transport.WalkRemoteObjectDatabase.ROOT_DIR; | |||
import java.io.BufferedOutputStream; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
@@ -26,6 +27,8 @@ import java.util.TreeMap; | |||
import org.eclipse.jgit.errors.TransportException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.internal.storage.file.PackFile; | |||
import org.eclipse.jgit.internal.storage.pack.PackExt; | |||
import org.eclipse.jgit.internal.storage.pack.PackWriter; | |||
import org.eclipse.jgit.lib.AnyObjectId; | |||
import org.eclipse.jgit.lib.Constants; | |||
@@ -189,9 +192,8 @@ class WalkPushConnection extends BaseConnection implements PushConnection { | |||
private void sendpack(final List<RemoteRefUpdate> updates, | |||
final ProgressMonitor monitor) throws TransportException { | |||
String pathPack = null; | |||
String pathIdx = null; | |||
PackFile pack = null; | |||
PackFile idx = null; | |||
try (PackWriter writer = new PackWriter(transport.getPackConfig(), | |||
local.newObjectReader())) { | |||
@@ -217,31 +219,33 @@ class WalkPushConnection extends BaseConnection implements PushConnection { | |||
for (String n : dest.getPackNames()) | |||
packNames.put(n, n); | |||
final String base = "pack-" + writer.computeName().name(); //$NON-NLS-1$ | |||
final String packName = base + ".pack"; //$NON-NLS-1$ | |||
pathPack = "pack/" + packName; //$NON-NLS-1$ | |||
pathIdx = "pack/" + base + ".idx"; //$NON-NLS-1$ //$NON-NLS-2$ | |||
File packDir = new File("pack"); //$NON-NLS-1$ | |||
pack = new PackFile(packDir, writer.computeName(), | |||
PackExt.PACK); | |||
idx = pack.create(PackExt.INDEX); | |||
if (packNames.remove(packName) != null) { | |||
if (packNames.remove(pack.getName()) != null) { | |||
// The remote already contains this pack. We should | |||
// remove the index before overwriting to prevent bad | |||
// offsets from appearing to clients. | |||
// | |||
dest.writeInfoPacks(packNames.keySet()); | |||
dest.deleteFile(pathIdx); | |||
dest.deleteFile(idx.getPath()); | |||
} | |||
// Write the pack file, then the index, as readers look the | |||
// other direction (index, then pack file). | |||
// | |||
String wt = "Put " + base.substring(0, 12); //$NON-NLS-1$ | |||
String wt = "Put " + pack.getName().substring(0, 12); //$NON-NLS-1$ | |||
try (OutputStream os = new BufferedOutputStream( | |||
dest.writeFile(pathPack, monitor, wt + "..pack"))) { //$NON-NLS-1$ | |||
dest.writeFile(pack.getPath(), monitor, | |||
wt + "." + pack.getPackExt().getExtension()))) { //$NON-NLS-1$ | |||
writer.writePack(monitor, monitor, os); | |||
} | |||
try (OutputStream os = new BufferedOutputStream( | |||
dest.writeFile(pathIdx, monitor, wt + "..idx"))) { //$NON-NLS-1$ | |||
dest.writeFile(idx.getPath(), monitor, | |||
wt + "." + idx.getPackExt().getExtension()))) { //$NON-NLS-1$ | |||
writer.writeIndex(os); | |||
} | |||
@@ -250,22 +254,22 @@ class WalkPushConnection extends BaseConnection implements PushConnection { | |||
// and discover the most recent objects there. | |||
// | |||
final ArrayList<String> infoPacks = new ArrayList<>(); | |||
infoPacks.add(packName); | |||
infoPacks.add(pack.getName()); | |||
infoPacks.addAll(packNames.keySet()); | |||
dest.writeInfoPacks(infoPacks); | |||
} catch (IOException err) { | |||
safeDelete(pathIdx); | |||
safeDelete(pathPack); | |||
safeDelete(idx); | |||
safeDelete(pack); | |||
throw new TransportException(uri, JGitText.get().cannotStoreObjects, err); | |||
} | |||
} | |||
private void safeDelete(String path) { | |||
private void safeDelete(File path) { | |||
if (path != null) { | |||
try { | |||
dest.deleteFile(path); | |||
dest.deleteFile(path.getPath()); | |||
} catch (IOException cleanupFailure) { | |||
// Ignore the deletion failure. We probably are | |||
// already failing and were just trying to pick |
@@ -202,6 +202,14 @@ | |||
<id>repo.eclipse.org.cbi-snapshots</id> | |||
<url>https://repo.eclipse.org/content/repositories/cbi-snapshots/</url> | |||
</pluginRepository> | |||
<pluginRepository> | |||
<id>repo.eclipse.org.dash-releases</id> | |||
<url>https://repo.eclipse.org/content/repositories/dash-licenses-releases/</url> | |||
</pluginRepository> | |||
<pluginRepository> | |||
<id>repo.eclipse.org.dash-snapshots</id> | |||
<url>https://repo.eclipse.org/content/repositories/dash-licenses-snapshots/</url> | |||
</pluginRepository> | |||
</pluginRepositories> | |||
<build> | |||
@@ -391,6 +399,11 @@ | |||
<artifactId>spring-boot-maven-plugin</artifactId> | |||
<version>2.4.1</version> | |||
</plugin> | |||
<plugin> | |||
<groupId>org.eclipse.dash</groupId> | |||
<artifactId>license-tool-plugin</artifactId> | |||
<version>0.0.1-SNAPSHOT</version> | |||
</plugin> | |||
</plugins> | |||
</pluginManagement> | |||
@@ -549,6 +562,10 @@ | |||
<groupId>org.apache.maven.plugins</groupId> | |||
<artifactId>maven-surefire-report-plugin</artifactId> | |||
</plugin> | |||
<plugin> | |||
<groupId>org.eclipse.dash</groupId> | |||
<artifactId>license-tool-plugin</artifactId> | |||
</plugin> | |||
</plugins> | |||
</build> | |||