From 835ab30743603055c9007f8d570073c39ddad236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Fri, 28 Feb 2014 18:34:59 +0100 Subject: [PATCH] Expose the received pack size in ReceivePack PostReceiveHooks can make use of this information to, for example, update a cached size of the Git repository. Change-Id: I2bf1200959a50531e2155a7609c96035ba45b10d Signed-off-by: Matthias Sohn --- .../jgit/http/test/MeasurePackSizeTest.java | 165 ++++++++++++++++++ .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/internal/JGitText.java | 1 + .../file/ObjectDirectoryPackParser.java | 15 ++ .../jgit/transport/BaseReceivePack.java | 20 +++ .../eclipse/jgit/transport/PackParser.java | 14 ++ 6 files changed, 216 insertions(+) create mode 100644 org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java new file mode 100644 index 000000000..108e7bb72 --- /dev/null +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/MeasurePackSizeTest.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2014, Matthias Sohn + * 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 v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.http.test; + +import static org.junit.Assert.assertEquals; + +import java.util.Collection; +import java.util.Collections; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.http.server.GitServlet; +import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; +import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.junit.http.HttpTestCase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.NullProgressMonitor; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.revwalk.RevBlob; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.PostReceiveHook; +import org.eclipse.jgit.transport.PushResult; +import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.transport.ReceivePack; +import org.eclipse.jgit.transport.RemoteRefUpdate; +import org.eclipse.jgit.transport.Transport; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.resolver.RepositoryResolver; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.junit.Before; +import org.junit.Test; + +public class MeasurePackSizeTest extends HttpTestCase { + private Repository remoteRepository; + + private URIish remoteURI; + + long packSize = -1; + + @Before + public void setUp() throws Exception { + super.setUp(); + + final TestRepository src = createTestRepository(); + final String srcName = src.getRepository().getDirectory().getName(); + + ServletContextHandler app = server.addContext("/git"); + GitServlet gs = new GitServlet(); + gs.setRepositoryResolver(new RepositoryResolver() { + public Repository open(HttpServletRequest req, String name) + throws RepositoryNotFoundException, + ServiceNotEnabledException { + if (!name.equals(srcName)) + throw new RepositoryNotFoundException(name); + + final Repository db = src.getRepository(); + db.incrementOpen(); + return db; + } + }); + gs.setReceivePackFactory(new DefaultReceivePackFactory() { + public ReceivePack create(HttpServletRequest req, Repository db) + throws ServiceNotEnabledException, + ServiceNotAuthorizedException { + ReceivePack recv = super.create(req, db); + recv.setPostReceiveHook(new PostReceiveHook() { + + public void onPostReceive(ReceivePack rp, + Collection commands) { + packSize = rp.getPackSize(); + } + }); + return recv; + } + + }); + app.addServlet(new ServletHolder(gs), "/*"); + + server.setUp(); + + remoteRepository = src.getRepository(); + remoteURI = toURIish(app, srcName); + + StoredConfig cfg = remoteRepository.getConfig(); + cfg.setBoolean("http", null, "receivepack", true); + cfg.save(); + } + + @Test + public void testPush_packSize() throws Exception { + final TestRepository src = createTestRepository(); + final RevBlob Q_txt = src + .blob("some blob content to measure pack size"); + final RevCommit Q = src.commit().add("Q", Q_txt).create(); + final Repository db = src.getRepository(); + final String dstName = Constants.R_HEADS + "new.branch"; + Transport t; + PushResult result; + + t = Transport.open(db, remoteURI); + try { + final String srcExpr = Q.name(); + final boolean forceUpdate = false; + final String localName = null; + final ObjectId oldId = null; + + RemoteRefUpdate update = new RemoteRefUpdate(src.getRepository(), + srcExpr, dstName, forceUpdate, localName, oldId); + result = t.push(NullProgressMonitor.INSTANCE, + Collections.singleton(update)); + } finally { + t.close(); + } + assertEquals("expected 1 RemoteUpdate", 1, result.getRemoteUpdates() + .size()); + assertEquals("unexpected pack size", 1398, packSize); + } + +} diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index a5a5cf6c9..57c08f369 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -378,6 +378,7 @@ packHasUnresolvedDeltas=pack has unresolved deltas packingCancelledDuringObjectsWriting=Packing cancelled during objects writing packObjectCountMismatch=Pack object count mismatch: pack {0} index {1}: {2} packRefs=Pack refs +packSizeNotSetYet=Pack size not yet set since it has not yet been received packTooLargeForIndexVersion1=Pack too large for index version 1 packWriterStatistics=Total {0,number,#0} (delta {1,number,#0}), reused {2,number,#0} (delta {3,number,#0}) panicCantRenameIndexFile=Panic: index file {0} must be renamed to replace {1}; until then repository is corrupt diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 8ca425a15..40e74ed89 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -440,6 +440,7 @@ public class JGitText extends TranslationBundle { /***/ public String packingCancelledDuringObjectsWriting; /***/ public String packObjectCountMismatch; /***/ public String packRefs; + /***/ public String packSizeNotSetYet; /***/ public String packTooLargeForIndexVersion1; /***/ public String packWriterStatistics; /***/ public String panicCantRenameIndexFile; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java index 1846c47ed..a186b8147 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryPackParser.java @@ -168,6 +168,21 @@ public class ObjectDirectoryPackParser extends PackParser { return newPack; } + @Override + public long getPackSize() { + if (newPack == null) + return super.getPackSize(); + + File pack = newPack.getPackFile(); + long size = pack.length(); + String p = pack.getAbsolutePath(); + String i = p.substring(0, p.length() - ".pack".length()) + ".idx"; //$NON-NLS-1$ //$NON-NLS-2$ + File idx = new File(i); + if (idx.exists() && idx.isFile()) + size += idx.length(); + return size; + } + @Override public PackLock parse(ProgressMonitor receiving, ProgressMonitor resolving) throws IOException { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java index 67ab9ef3a..68b3262a0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java @@ -240,6 +240,9 @@ public abstract class BaseReceivePack { /** Total pack size limit */ private long maxPackSizeLimit = -1; + /** The size of the received pack, including index size */ + private Long packSize; + /** * Create a new pack receive for an open repository. * @@ -720,6 +723,22 @@ public abstract class BaseReceivePack { return msgOutWrapper; } + /** + * Get the size of the received pack file including the index size. + * + * This can only be called if the pack is already received. + * + * @return the size of the received pack including index size + * @throws IllegalStateException + * if called before the pack has been received + * @since 3.3 + */ + public long getPackSize() { + if (packSize != null) + return packSize.longValue(); + throw new IllegalStateException(JGitText.get().packSizeNotSetYet); + } + /** @return true if any commands to be executed have been read. */ protected boolean hasCommands() { return !commands.isEmpty(); @@ -968,6 +987,7 @@ public abstract class BaseReceivePack { parser.setLockMessage(lockMsg); parser.setMaxObjectSizeLimit(maxObjectSizeLimit); packLock = parser.parse(receiving, resolving); + packSize = Long.valueOf(parser.getPackSize()); ins.flush(); } finally { ins.release(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java index e16cce0e3..93522c1e9 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java @@ -418,6 +418,20 @@ public abstract class PackParser { return list; } + /** + * Get the size of the parsed pack. + * + * This will also include the pack index size if an index was created. This + * method should only be called after pack parsing is finished. + * + * @return the pack size (including the index size) or -1 if the size cannot + * be determined + * @since 3.3 + */ + public long getPackSize() { + return -1; + } + /** * Parse the pack stream. *