Bugfix: Conflict in pack parser (#1518)

The change tackles a sporadic error in integration tests, where during or after a change in a git repository a pack file could not be read correctly due to a "short compressed stream". The exception could look like this:

ERROR org.eclipse.jgit.internal.storage.file.ObjectDirectory - Exception caught while accessing pack file scm-home/repositories/8gSNr4ogc5X/data/objects/pack/pack-51a3500283ece83ab8efa7edfb9370e6f97311b5.pack, the pack file might be corrupt. Caught 1 consecutive errors while trying to read this pack.
java.io.EOFException: Short compressed stream at 197
	at org.eclipse.jgit.internal.storage.file.PackFile.decompress(PackFile.java:381)
	at org.eclipse.jgit.internal.storage.file.PackFile.load(PackFile.java:815)
	at org.eclipse.jgit.internal.storage.file.PackFile.get(PackFile.java:284)
	at org.eclipse.jgit.internal.storage.file.ObjectDirectory.openPackedObject(ObjectDirectory.java:455)
	at org.eclipse.jgit.internal.storage.file.ObjectDirectory.openPackedFromSelfOrAlternate(ObjectDirectory.java:413)
	at org.eclipse.jgit.internal.storage.file.ObjectDirectory.openObject(ObjectDirectory.java:404)
	at org.eclipse.jgit.internal.storage.file.WindowCursor.open(WindowCursor.java:132)
	at org.eclipse.jgit.treewalk.CanonicalTreeParser.reset(CanonicalTreeParser.java:191)
	at org.eclipse.jgit.treewalk.TreeWalk.parserFor(TreeWalk.java:1344)
	at org.eclipse.jgit.treewalk.TreeWalk.addTree(TreeWalk.java:732)
	at sonia.scm.repository.spi.Differ.create(Differ.java:102)
	at sonia.scm.repository.spi.Differ.diff(Differ.java:63)
We found out that this seems to be linked to the asynchronous execution of post commit hooks, that originally are triggered in the midst of the processing of a receive pack.

With this change the fireing of these triggers is delayed until the end of the internal git processing. The central class for this is the GitHookEventFacade, where hook events are either

- put into a ThreadLocal, so that they can be triggered later, or
- triggered in a thread that is joined with an internal JGit thread for internal pushes (eg. for modify command or merge command)
This commit is contained in:
René Pfeuffer
2021-02-03 11:08:13 +01:00
committed by GitHub
parent 4fba5cc17b
commit 7a7ac9a3f2
13 changed files with 218 additions and 87 deletions

View File

@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package sonia.scm.web;
import com.google.common.annotations.VisibleForTesting;
@@ -68,27 +68,17 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
//~--- constructors ---------------------------------------------------------
/**
* Constructs ...
*
*
*
* @param repositoryResolver
* @param receivePackFactory
* @param repositoryViewer
* @param repositoryRequestListenerUtil
* @param lfsServletFactory
*/
@Inject
public ScmGitServlet(GitRepositoryResolver repositoryResolver,
GitReceivePackFactory receivePackFactory,
GitRepositoryViewer repositoryViewer,
RepositoryRequestListenerUtil repositoryRequestListenerUtil,
LfsServletFactory lfsServletFactory)
LfsServletFactory lfsServletFactory, GitHookEventFacade gitHookEventFacade)
{
this.repositoryViewer = repositoryViewer;
this.repositoryRequestListenerUtil = repositoryRequestListenerUtil;
this.lfsServletFactory = lfsServletFactory;
this.gitHookEventFacade = gitHookEventFacade;
setRepositoryResolver(repositoryResolver);
setReceivePackFactory(receivePackFactory);
@@ -109,7 +99,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
@Override
public void service(HttpServletRequest request, HttpServletResponse response, Repository repository)
throws ServletException, IOException
{
{
String repoPath = repository.getNamespace() + "/" + repository.getName();
logger.trace("handle git repository at {}", repoPath);
if (isLfsBatchApiRequest(request, repoPath)) {
@@ -123,17 +113,22 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
} else if (isRegularGitAPIRequest(request)) {
logger.trace("handle regular git request");
// continue with the regular git Backend
handleRegularGitRequest(request, response, repository);
try {
handleRegularGitRequest(request, response, repository);
gitHookEventFacade.firePending();
} finally {
gitHookEventFacade.clean();
}
} else {
logger.trace("handle browser request");
handleBrowserRequest(request, response, repository);
}
}
private boolean isRegularGitAPIRequest(HttpServletRequest request) {
return REGEX_GITHTTPBACKEND.matcher(HttpUtil.getStrippedURI(request)).matches();
}
private void handleGitLfsRequest(HttpServlet servlet, HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
if (repositoryRequestListenerUtil.callListeners(request, response, repository)) {
servlet.service(request, response);
@@ -141,7 +136,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
logger.debug("request aborted by repository request listener");
}
}
private void handleRegularGitRequest(HttpServletRequest request, HttpServletResponse response, Repository repository) throws ServletException, IOException {
if (repositoryRequestListenerUtil.callListeners(request, response, repository)) {
super.service(request, response);
@@ -149,7 +144,7 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
logger.debug("request aborted by repository request listener");
}
}
/**
* This method renders basic information about the repository into the response. The result is meant to be viewed by
@@ -245,4 +240,6 @@ public class ScmGitServlet extends GitServlet implements ScmProviderHttpServlet
private final GitRepositoryViewer repositoryViewer;
private final LfsServletFactory lfsServletFactory;
private final GitHookEventFacade gitHookEventFacade;
}