Update JGit to 3.4.1.201406201815-r.112-g112f6e3

This version of JGit fixes the recursive merger on all storage
systems.  Objects created during the virtual base construction of a
recursive merge must be written out somewhere and made available
through an ObjectReader for later passes to work on.

In both local filesystem and DFS implementations Gerrit was no-op'ing
the inserter in dry-run mode, causing these objects to be lost and
unavailable during the later processing stages of the merger.  With a
virtual common ancestor tree or blob missing, the dry-run merger fails
and a spurious merge conflict is reported.

Instead build a non-flushing inserter wrapper around a real inserter
for the repository. On local disk (standard storage) this will allow
the virtual base to write loose objects, which may be reclaimed in
about two weeks by the standard `git prune` invoked by `git gc`.

On DFS systems this will create a new pack file and buffer a block of
data in memory before starting to store to persistent storage.
However with no flush() the DfsInserter will attempt to rollback the
pack, which may allow the DFS system to reclaim its storage quickly.
Some implementations of DFS may buffer even more deeply than one
block, making the discard even cheaper for smaller merges.

This update also fixes a potential infinite loop during object
inflation within both the WindowCursor or DfsReader versions of
ObjectReader.  Inflation could get stuck if an object's compression
stream within a pack ended at a very precise alignment with the cache
block size.  The alignment problem is very rare, as it has taken
several years to identify and track down.

Change-Id: I9859bd073bd710424e12b8b091abb8278f4f9fcc
This commit is contained in:
Shawn Pearce
2014-08-13 22:06:49 -07:00
parent 0a07fe3a36
commit 0a3372a4d2
4 changed files with 25 additions and 21 deletions

View File

@@ -15,13 +15,18 @@
package com.google.gerrit.acceptance.git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.junit.Before;
import java.io.IOException;
import java.net.URISyntaxException;
public class HttpPushForReviewIT extends AbstractPushForReview {
@Before
public void selectHttpUrl() throws GitAPIException, IOException {
public void selectHttpUrl() throws GitAPIException, IOException, URISyntaxException {
CredentialsProvider.setDefault(new UsernamePasswordCredentialsProvider(
admin.username, admin.httpPassword));
selectProtocol(Protocol.HTTP);
}
}

View File

@@ -218,7 +218,7 @@ public class ChangeKindCacheImpl implements ChangeKindCache {
// having the same tree as would exist when the prior commit is
// cherry-picked onto the next commit's new first parent.
ThreeWayMerger merger = MergeUtil.newThreeWayMerger(
key.repo, MergeUtil.createDryRunInserter(), key.strategyName);
key.repo, MergeUtil.createDryRunInserter(key.repo), key.strategyName);
merger.setBase(prior.getParent(0));
if (merger.merge(next.getParent(0), prior)
&& merger.getResultTreeId().equals(next.getTree())) {

View File

@@ -394,7 +394,7 @@ public class MergeUtil {
return false;
}
final ThreeWayMerger m = newThreeWayMerger(repo, createDryRunInserter());
ThreeWayMerger m = newThreeWayMerger(repo, createDryRunInserter(repo));
try {
return m.merge(new AnyObjectId[] {mergeTip, toMerge});
} catch (LargeObjectException e) {
@@ -443,8 +443,7 @@ public class MergeUtil {
// that on the current merge tip.
//
try {
final ThreeWayMerger m =
newThreeWayMerger(repo, createDryRunInserter());
ThreeWayMerger m = newThreeWayMerger(repo, createDryRunInserter(repo));
m.setBase(toMerge.getParent(0));
return m.merge(mergeTip, toMerge);
} catch (IOException e) {
@@ -471,12 +470,12 @@ public class MergeUtil {
}
}
public static ObjectInserter createDryRunInserter() {
return new ObjectInserter() {
public static ObjectInserter createDryRunInserter(Repository db) {
final ObjectInserter delegate = db.newObjectInserter();
return new ObjectInserter.Filter() {
@Override
public ObjectId insert(int objectType, long length, InputStream in)
throws IOException {
return idFor(objectType, length, in);
protected ObjectInserter delegate() {
return delegate;
}
@Override
@@ -488,11 +487,6 @@ public class MergeUtil {
public void flush() throws IOException {
// Do nothing.
}
@Override
public void release() {
// Do nothing.
}
};
}

View File

@@ -1,12 +1,14 @@
include_defs('//lib/maven.defs')
VERS = '3.4.0.201406110918-r'
VERS = '3.4.1.201406201815-r.112-g112f6e3'
REPO = GERRIT
maven_jar(
name = 'jgit',
id = 'org.eclipse.jgit:org.eclipse.jgit:' + VERS,
bin_sha1 = '60e74a29895be82ec7bd1fbb6304975e92b955a5',
src_sha1 = '69adaa263e2b5c21a84a25105c0c93761bdd8a80',
repository = REPO,
bin_sha1 = 'e1768c0b0977acb165fe759e90484feedc9bf699',
src_sha1 = '075d8c4185167159f6f359fd747a7172b325fdef',
license = 'jgit',
unsign = True,
deps = [':ewah'],
@@ -20,7 +22,8 @@ maven_jar(
maven_jar(
name = 'jgit-servlet',
id = 'org.eclipse.jgit:org.eclipse.jgit.http.server:' + VERS,
sha1 = '5c778052a90520a970041f2f51e89cac9cf2cb3f',
repository = REPO,
sha1 = '753e1aa37d60589b373c8290bde20a112d08dea0',
license = 'jgit',
deps = [':jgit'],
unsign = True,
@@ -33,7 +36,8 @@ maven_jar(
maven_jar(
name = 'jgit-archive',
id = 'org.eclipse.jgit:org.eclipse.jgit.archive:' + VERS,
sha1 = '8644e0dde6127c2d1b5a4fa902bf9b534764e969',
repository = REPO,
sha1 = 'a8294e04c1a15d84436d780497db1ddfb69f6e97',
license = 'jgit',
deps = [':jgit',
'//lib/commons:compress',
@@ -49,7 +53,8 @@ maven_jar(
maven_jar(
name = 'junit',
id = 'org.eclipse.jgit:org.eclipse.jgit.junit:' + VERS,
sha1 = '4d1232e8b2412521d707d741ca14db9fc6806db2',
repository = REPO,
sha1 = 'b4e635996ac9ab2658f4981376aedefb712c83ed',
license = 'DO_NOT_DISTRIBUTE',
unsign = True,
deps = [':jgit'],