Ensure RevWalk is released when done

Update a number of calling sites of RevWalk to ensure the walker's
internal ObjectReader is released after the walk is no longer used.
Because the ObjectReader is likely to hold onto a native resource
like an Inflater, we don't want to leak them outside of their
useful scope.

Where possible we also try to share ObjectReaders across several
walk pools, or between a walker and a PackWriter.  This permits
the ObjectReader to actually do some caching if it felt inclined
to do so.

Not everything was updated, we'll probably need to come back and
update even more call sites, but these are some of the biggest
offenders.  Test cases in particular aren't updated.  My plan is to
move most storage-agnostic tests onto some purely in-memory storage
solution that doesn't do compression.

Change-Id: I04087ec79faeea208b19848939898ad7172b6672
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2010-06-29 15:12:51 -07:00
parent 4913ad57fc
commit 515deaf7e5
17 changed files with 298 additions and 184 deletions

View File

@ -74,30 +74,35 @@ public void doGet(final HttpServletRequest req,
final Repository db = getRepository(req); final Repository db = getRepository(req);
final RevWalk walk = new RevWalk(db); final RevWalk walk = new RevWalk(db);
final RevFlag ADVERTISED = walk.newFlag("ADVERTISED"); try {
final RevFlag ADVERTISED = walk.newFlag("ADVERTISED");
final OutputStreamWriter out = new OutputStreamWriter( final OutputStreamWriter out = new OutputStreamWriter(
new SmartOutputStream(req, rsp), Constants.CHARSET); new SmartOutputStream(req, rsp), Constants.CHARSET);
final RefAdvertiser adv = new RefAdvertiser() { final RefAdvertiser adv = new RefAdvertiser() {
@Override @Override
protected void writeOne(final CharSequence line) throws IOException { protected void writeOne(final CharSequence line)
// Whoever decided that info/refs should use a different throws IOException {
// delimiter than the native git:// protocol shouldn't // Whoever decided that info/refs should use a different
// be allowed to design this sort of stuff. :-( // delimiter than the native git:// protocol shouldn't
out.append(line.toString().replace(' ', '\t')); // be allowed to design this sort of stuff. :-(
} out.append(line.toString().replace(' ', '\t'));
}
@Override @Override
protected void end() { protected void end() {
// No end marker required for info/refs format. // No end marker required for info/refs format.
} }
}; };
adv.init(walk, ADVERTISED); adv.init(walk, ADVERTISED);
adv.setDerefTags(true); adv.setDerefTags(true);
Map<String, Ref> refs = db.getAllRefs(); Map<String, Ref> refs = db.getAllRefs();
refs.remove(Constants.HEAD); refs.remove(Constants.HEAD);
adv.send(refs); adv.send(refs);
out.close(); out.close();
} finally {
walk.release();
}
} }
} }

View File

@ -83,7 +83,12 @@ static class InfoRefs extends SmartServiceInfoRefs {
protected void advertise(HttpServletRequest req, Repository db, protected void advertise(HttpServletRequest req, Repository db,
PacketLineOutRefAdvertiser pck) throws IOException, PacketLineOutRefAdvertiser pck) throws IOException,
ServiceNotEnabledException, ServiceNotAuthorizedException { ServiceNotEnabledException, ServiceNotAuthorizedException {
receivePackFactory.create(req, db).sendAdvertisedRefs(pck); ReceivePack rp = receivePackFactory.create(req, db);
try {
rp.sendAdvertisedRefs(pck);
} finally {
rp.getRevWalk().release();
}
} }
} }

View File

@ -83,7 +83,12 @@ static class InfoRefs extends SmartServiceInfoRefs {
protected void advertise(HttpServletRequest req, Repository db, protected void advertise(HttpServletRequest req, Repository db,
PacketLineOutRefAdvertiser pck) throws IOException, PacketLineOutRefAdvertiser pck) throws IOException,
ServiceNotEnabledException, ServiceNotAuthorizedException { ServiceNotEnabledException, ServiceNotAuthorizedException {
uploadPackFactory.create(req, db).sendAdvertisedRefs(pck); UploadPack up = uploadPackFactory.create(req, db);
try {
up.sendAdvertisedRefs(pck);
} finally {
up.getRevWalk().release();
}
} }
} }

View File

@ -297,6 +297,7 @@ private Map<String, Ref> computeNewRefs() throws IOException {
name, id)); name, id));
} }
} finally { } finally {
rw.release();
br.close(); br.close();
} }
return refs; return refs;

View File

@ -160,38 +160,42 @@ public RevCommit call() throws NoHeadException, NoMessageException,
.format(commit)); .format(commit));
odi.flush(); odi.flush();
RevCommit revCommit = new RevWalk(repo) RevWalk revWalk = new RevWalk(repo);
.parseCommit(commitId); try {
RefUpdate ru = repo.updateRef(Constants.HEAD); RevCommit revCommit = revWalk.parseCommit(commitId);
ru.setNewObjectId(commitId); RefUpdate ru = repo.updateRef(Constants.HEAD);
ru.setRefLogMessage("commit : " ru.setNewObjectId(commitId);
+ revCommit.getShortMessage(), false); ru.setRefLogMessage("commit : "
+ revCommit.getShortMessage(), false);
ru.setExpectedOldObjectId(headId); ru.setExpectedOldObjectId(headId);
Result rc = ru.update(); Result rc = ru.update();
switch (rc) { switch (rc) {
case NEW: case NEW:
case FAST_FORWARD: { case FAST_FORWARD: {
setCallable(false); setCallable(false);
File meta = repo.getDirectory(); File meta = repo.getDirectory();
if (state == RepositoryState.MERGING_RESOLVED if (state == RepositoryState.MERGING_RESOLVED
&& meta != null) { && meta != null) {
// Commit was successful. Now delete the files // Commit was successful. Now delete the files
// used for merge commits // used for merge commits
new File(meta, Constants.MERGE_HEAD).delete(); new File(meta, Constants.MERGE_HEAD).delete();
new File(meta, Constants.MERGE_MSG).delete(); new File(meta, Constants.MERGE_MSG).delete();
}
return revCommit;
} }
return revCommit; case REJECTED:
} case LOCK_FAILURE:
case REJECTED: throw new ConcurrentRefUpdateException(JGitText
case LOCK_FAILURE: .get().couldNotLockHEAD, ru.getRef(), rc);
throw new ConcurrentRefUpdateException( default:
JGitText.get().couldNotLockHEAD, ru.getRef(), throw new JGitInternalException(MessageFormat
rc); .format(JGitText.get().updatingRefFailed,
default: Constants.HEAD,
throw new JGitInternalException(MessageFormat.format( commitId.toString(), rc));
JGitText.get().updatingRefFailed, }
Constants.HEAD, commitId.toString(), rc)); } finally {
revWalk.release();
} }
} finally { } finally {
odi.release(); odi.release();

View File

@ -119,37 +119,41 @@ public MergeResult call() throws NoHeadException,
// Check for FAST_FORWARD, ALREADY_UP_TO_DATE // Check for FAST_FORWARD, ALREADY_UP_TO_DATE
RevWalk revWalk = new RevWalk(repo); RevWalk revWalk = new RevWalk(repo);
RevCommit headCommit = revWalk.lookupCommit(head.getObjectId()); try {
RevCommit headCommit = revWalk.lookupCommit(head.getObjectId());
Ref ref = commits.get(0); Ref ref = commits.get(0);
refLogMessage.append(ref.getName()); refLogMessage.append(ref.getName());
// handle annotated tags // handle annotated tags
ObjectId objectId = ref.getPeeledObjectId(); ObjectId objectId = ref.getPeeledObjectId();
if (objectId == null) if (objectId == null)
objectId = ref.getObjectId(); objectId = ref.getObjectId();
RevCommit srcCommit = revWalk.lookupCommit(objectId); RevCommit srcCommit = revWalk.lookupCommit(objectId);
if (revWalk.isMergedInto(srcCommit, headCommit)) { if (revWalk.isMergedInto(srcCommit, headCommit)) {
setCallable(false); setCallable(false);
return new MergeResult(headCommit, return new MergeResult(headCommit,
MergeStatus.ALREADY_UP_TO_DATE, mergeStrategy); MergeStatus.ALREADY_UP_TO_DATE, mergeStrategy);
} else if (revWalk.isMergedInto(headCommit, srcCommit)) { } else if (revWalk.isMergedInto(headCommit, srcCommit)) {
// FAST_FORWARD detected: skip doing a real merge but only // FAST_FORWARD detected: skip doing a real merge but only
// update HEAD // update HEAD
refLogMessage.append(": " + MergeStatus.FAST_FORWARD); refLogMessage.append(": " + MergeStatus.FAST_FORWARD);
checkoutNewHead(revWalk, headCommit, srcCommit); checkoutNewHead(revWalk, headCommit, srcCommit);
updateHead(refLogMessage, srcCommit, head.getObjectId()); updateHead(refLogMessage, srcCommit, head.getObjectId());
setCallable(false); setCallable(false);
return new MergeResult(srcCommit, MergeStatus.FAST_FORWARD, return new MergeResult(srcCommit, MergeStatus.FAST_FORWARD,
mergeStrategy); mergeStrategy);
} else { } else {
return new MergeResult( return new MergeResult(
headCommit, headCommit,
MergeResult.MergeStatus.NOT_SUPPORTED, MergeResult.MergeStatus.NOT_SUPPORTED,
mergeStrategy, mergeStrategy,
JGitText.get().onlyAlreadyUpToDateAndFastForwardMergesAreAvailable); JGitText.get().onlyAlreadyUpToDateAndFastForwardMergesAreAvailable);
}
} finally {
revWalk.release();
} }
} catch (IOException e) { } catch (IOException e) {
throw new JGitInternalException( throw new JGitInternalException(

View File

@ -440,7 +440,12 @@ public Result forceUpdate() throws IOException {
* an unexpected IO error occurred while writing changes. * an unexpected IO error occurred while writing changes.
*/ */
public Result update() throws IOException { public Result update() throws IOException {
return update(new RevWalk(getRepository())); RevWalk rw = new RevWalk(getRepository());
try {
return update(rw);
} finally {
rw.release();
}
} }
/** /**
@ -485,7 +490,12 @@ Result execute(Result status) throws IOException {
* @throws IOException * @throws IOException
*/ */
public Result delete() throws IOException { public Result delete() throws IOException {
return delete(new RevWalk(getRepository())); RevWalk rw = new RevWalk(getRepository());
try {
return delete(rw);
} finally {
rw.release();
}
} }
/** /**

View File

@ -484,9 +484,17 @@ public RefRename renameRef(final String fromRef, final String toRef) throws IOEx
* on serious errors * on serious errors
*/ */
public ObjectId resolve(final String revstr) throws IOException { public ObjectId resolve(final String revstr) throws IOException {
RevWalk rw = new RevWalk(this);
try {
return resolve(rw, revstr);
} finally {
rw.release();
}
}
private ObjectId resolve(final RevWalk rw, final String revstr) throws IOException {
char[] rev = revstr.toCharArray(); char[] rev = revstr.toCharArray();
RevObject ref = null; RevObject ref = null;
RevWalk rw = new RevWalk(this);
for (int i = 0; i < rev.length; ++i) { for (int i = 0; i < rev.length; ++i) {
switch (rev[i]) { switch (rev[i]) {
case '^': case '^':

View File

@ -74,6 +74,7 @@
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import org.eclipse.jgit.JGitText; import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.ObjectWritingException; import org.eclipse.jgit.errors.ObjectWritingException;
import org.eclipse.jgit.events.RefsChangedEvent; import org.eclipse.jgit.events.RefsChangedEvent;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -418,16 +419,7 @@ public Ref peel(final Ref ref) throws IOException {
if (leaf.isPeeled() || leaf.getObjectId() == null) if (leaf.isPeeled() || leaf.getObjectId() == null)
return ref; return ref;
RevWalk rw = new RevWalk(getRepository()); ObjectIdRef newLeaf = doPeel(leaf);
RevObject obj = rw.parseAny(leaf.getObjectId());
ObjectIdRef newLeaf;
if (obj instanceof RevTag) {
newLeaf = new ObjectIdRef.PeeledTag(leaf.getStorage(), leaf
.getName(), leaf.getObjectId(), rw.peel(obj).copy());
} else {
newLeaf = new ObjectIdRef.PeeledNonTag(leaf.getStorage(), leaf
.getName(), leaf.getObjectId());
}
// Try to remember this peeling in the cache, so we don't have to do // Try to remember this peeling in the cache, so we don't have to do
// it again in the future, but only if the reference is unchanged. // it again in the future, but only if the reference is unchanged.
@ -444,6 +436,23 @@ public Ref peel(final Ref ref) throws IOException {
return recreate(ref, newLeaf); return recreate(ref, newLeaf);
} }
private ObjectIdRef doPeel(final Ref leaf) throws MissingObjectException,
IOException {
RevWalk rw = new RevWalk(getRepository());
try {
RevObject obj = rw.parseAny(leaf.getObjectId());
if (obj instanceof RevTag) {
return new ObjectIdRef.PeeledTag(leaf.getStorage(), leaf
.getName(), leaf.getObjectId(), rw.peel(obj).copy());
} else {
return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), leaf
.getName(), leaf.getObjectId());
}
} finally {
rw.release();
}
}
private static Ref recreate(final Ref old, final ObjectIdRef leaf) { private static Ref recreate(final Ref old, final ObjectIdRef leaf) {
if (old.isSymbolic()) { if (old.isSymbolic()) {
Ref dst = recreate(old.getTarget(), leaf); Ref dst = recreate(old.getTarget(), leaf);

View File

@ -92,10 +92,10 @@ protected Result doRename() throws IOException {
if (source.getRef().isSymbolic()) if (source.getRef().isSymbolic())
return Result.IO_FAILURE; // not supported return Result.IO_FAILURE; // not supported
final RevWalk rw = new RevWalk(refdb.getRepository());
objId = source.getOldObjectId(); objId = source.getOldObjectId();
updateHEAD = needToUpdateHEAD(); updateHEAD = needToUpdateHEAD();
tmp = refdb.newTemporaryUpdate(); tmp = refdb.newTemporaryUpdate();
final RevWalk rw = new RevWalk(refdb.getRepository());
try { try {
// First backup the source so its never unreachable. // First backup the source so its never unreachable.
tmp.setNewObjectId(objId); tmp.setNewObjectId(objId);
@ -177,6 +177,7 @@ protected Result doRename() throws IOException {
} catch (IOException err) { } catch (IOException err) {
refdb.fileFor(tmp.getName()).delete(); refdb.fileFor(tmp.getName()).delete();
} }
rw.release();
} }
} }

View File

@ -63,6 +63,7 @@
import org.eclipse.jgit.errors.MissingObjectException; import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig; import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
@ -181,8 +182,6 @@ public class PackWriter {
// edge objects for thin packs // edge objects for thin packs
private final ObjectIdSubclassMap<ObjectId> edgeObjects = new ObjectIdSubclassMap<ObjectId>(); private final ObjectIdSubclassMap<ObjectId> edgeObjects = new ObjectIdSubclassMap<ObjectId>();
private final Repository db;
private final Deflater deflater; private final Deflater deflater;
private final ObjectReader reader; private final ObjectReader reader;
@ -218,19 +217,51 @@ public class PackWriter {
* repository where objects are stored. * repository where objects are stored.
*/ */
public PackWriter(final Repository repo) { public PackWriter(final Repository repo) {
this.db = repo; this(repo, repo.newObjectReader());
}
reader = db.newObjectReader(); /**
* Create a writer to load objects from the specified reader.
* <p>
* Objects for packing are specified in {@link #preparePack(Iterator)} or
* {@link #preparePack(ProgressMonitor, Collection, Collection)}.
*
* @param reader
* reader to read from the repository with.
*/
public PackWriter(final ObjectReader reader) {
this(null, reader);
}
/**
* Create writer for specified repository.
* <p>
* Objects for packing are specified in {@link #preparePack(Iterator)} or
* {@link #preparePack(ProgressMonitor, Collection, Collection)}.
*
* @param repo
* repository where objects are stored.
* @param reader
* reader to read from the repository with.
*/
public PackWriter(final Repository repo, final ObjectReader reader) {
this.reader = reader;
if (reader instanceof ObjectReuseAsIs) if (reader instanceof ObjectReuseAsIs)
reuseSupport = ((ObjectReuseAsIs) reader); reuseSupport = ((ObjectReuseAsIs) reader);
else else
reuseSupport = null; reuseSupport = null;
final CoreConfig coreConfig = db.getConfig().get(CoreConfig.KEY); final CoreConfig coreConfig = configOf(repo).get(CoreConfig.KEY);
this.deflater = new Deflater(coreConfig.getCompression()); deflater = new Deflater(coreConfig.getCompression());
outputVersion = coreConfig.getPackIndexVersion(); outputVersion = coreConfig.getPackIndexVersion();
} }
private static Config configOf(final Repository repo) {
if (repo == null)
return new Config();
return repo.getConfig();
}
/** /**
* Check whether object is configured to reuse deltas existing in * Check whether object is configured to reuse deltas existing in
* repository. * repository.

View File

@ -270,6 +270,12 @@ protected void doFetch(final ProgressMonitor monitor,
} }
} }
@Override
public void close() {
walk.release();
super.close();
}
private int maxTimeWanted(final Collection<Ref> wants) { private int maxTimeWanted(final Collection<Ref> wants) {
int maxTime = 0; int maxTime = 0;
for (final Ref r : wants) { for (final Ref r : wants) {

View File

@ -213,57 +213,65 @@ private void verifyPrerequisites() throws TransportException {
return; return;
final RevWalk rw = new RevWalk(transport.local); final RevWalk rw = new RevWalk(transport.local);
final RevFlag PREREQ = rw.newFlag("PREREQ");
final RevFlag SEEN = rw.newFlag("SEEN");
final Map<ObjectId, String> missing = new HashMap<ObjectId, String>();
final List<RevObject> commits = new ArrayList<RevObject>();
for (final Map.Entry<ObjectId, String> e : prereqs.entrySet()) {
ObjectId p = e.getKey();
try {
final RevCommit c = rw.parseCommit(p);
if (!c.has(PREREQ)) {
c.add(PREREQ);
commits.add(c);
}
} catch (MissingObjectException notFound) {
missing.put(p, e.getValue());
} catch (IOException err) {
throw new TransportException(transport.uri
, MessageFormat.format(JGitText.get().cannotReadCommit, p.name()), err);
}
}
if (!missing.isEmpty())
throw new MissingBundlePrerequisiteException(transport.uri, missing);
for (final Ref r : transport.local.getAllRefs().values()) {
try {
rw.markStart(rw.parseCommit(r.getObjectId()));
} catch (IOException readError) {
// If we cannot read the value of the ref skip it.
}
}
int remaining = commits.size();
try { try {
RevCommit c; final RevFlag PREREQ = rw.newFlag("PREREQ");
while ((c = rw.next()) != null) { final RevFlag SEEN = rw.newFlag("SEEN");
if (c.has(PREREQ)) {
c.add(SEEN); final Map<ObjectId, String> missing = new HashMap<ObjectId, String>();
if (--remaining == 0) final List<RevObject> commits = new ArrayList<RevObject>();
break; for (final Map.Entry<ObjectId, String> e : prereqs.entrySet()) {
ObjectId p = e.getKey();
try {
final RevCommit c = rw.parseCommit(p);
if (!c.has(PREREQ)) {
c.add(PREREQ);
commits.add(c);
}
} catch (MissingObjectException notFound) {
missing.put(p, e.getValue());
} catch (IOException err) {
throw new TransportException(transport.uri, MessageFormat
.format(JGitText.get().cannotReadCommit, p.name()),
err);
} }
} }
} catch (IOException err) { if (!missing.isEmpty())
throw new TransportException(transport.uri, JGitText.get().cannotReadObject, err); throw new MissingBundlePrerequisiteException(transport.uri,
} missing);
if (remaining > 0) { for (final Ref r : transport.local.getAllRefs().values()) {
for (final RevObject o : commits) { try {
if (!o.has(SEEN)) rw.markStart(rw.parseCommit(r.getObjectId()));
missing.put(o, prereqs.get(o)); } catch (IOException readError) {
// If we cannot read the value of the ref skip it.
}
} }
throw new MissingBundlePrerequisiteException(transport.uri, missing);
int remaining = commits.size();
try {
RevCommit c;
while ((c = rw.next()) != null) {
if (c.has(PREREQ)) {
c.add(SEEN);
if (--remaining == 0)
break;
}
}
} catch (IOException err) {
throw new TransportException(transport.uri,
JGitText.get().cannotReadObject, err);
}
if (remaining > 0) {
for (final RevObject o : commits) {
if (!o.has(SEEN))
missing.put(o, prereqs.get(o));
}
throw new MissingBundlePrerequisiteException(transport.uri,
missing);
}
} finally {
rw.release();
} }
} }

View File

@ -176,16 +176,21 @@ else if (tagopt == TagOpt.FETCH_TAGS)
} }
final RevWalk walk = new RevWalk(transport.local); final RevWalk walk = new RevWalk(transport.local);
if (transport.isRemoveDeletedRefs()) try {
deleteStaleTrackingRefs(result, walk); if (transport.isRemoveDeletedRefs())
for (TrackingRefUpdate u : localUpdates) { deleteStaleTrackingRefs(result, walk);
try { for (TrackingRefUpdate u : localUpdates) {
u.update(walk); try {
result.add(u); u.update(walk);
} catch (IOException err) { result.add(u);
throw new TransportException(MessageFormat.format( } catch (IOException err) {
JGitText.get().failureUpdatingTrackingRef, u.getLocalName(), err.getMessage()), err); throw new TransportException(MessageFormat.format(JGitText
.get().failureUpdatingTrackingRef,
u.getLocalName(), err.getMessage()), err);
}
} }
} finally {
walk.release();
} }
if (!fetchHeadUpdates.isEmpty()) { if (!fetchHeadUpdates.isEmpty()) {
@ -296,11 +301,15 @@ private void updateFETCH_HEAD(final FetchResult result) throws IOException {
private boolean askForIsComplete() throws TransportException { private boolean askForIsComplete() throws TransportException {
try { try {
final ObjectWalk ow = new ObjectWalk(transport.local); final ObjectWalk ow = new ObjectWalk(transport.local);
for (final ObjectId want : askFor.keySet()) try {
ow.markStart(ow.parseAny(want)); for (final ObjectId want : askFor.keySet())
for (final Ref ref : transport.local.getAllRefs().values()) ow.markStart(ow.parseAny(want));
ow.markUninteresting(ow.parseAny(ref.getObjectId())); for (final Ref ref : transport.local.getAllRefs().values())
ow.checkConnectivity(); ow.markUninteresting(ow.parseAny(ref.getObjectId()));
ow.checkConnectivity();
} finally {
ow.release();
}
return true; return true;
} catch (MissingObjectException e) { } catch (MissingObjectException e) {
return false; return false;

View File

@ -122,32 +122,38 @@ class PushProcess {
*/ */
PushResult execute(final ProgressMonitor monitor) PushResult execute(final ProgressMonitor monitor)
throws NotSupportedException, TransportException { throws NotSupportedException, TransportException {
monitor.beginTask(PROGRESS_OPENING_CONNECTION, ProgressMonitor.UNKNOWN);
final PushResult res = new PushResult();
connection = transport.openPush();
try { try {
res.setAdvertisedRefs(transport.getURI(), connection.getRefsMap()); monitor.beginTask(PROGRESS_OPENING_CONNECTION,
res.setRemoteUpdates(toPush); ProgressMonitor.UNKNOWN);
monitor.endTask();
final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates(); final PushResult res = new PushResult();
if (transport.isDryRun()) connection = transport.openPush();
modifyUpdatesForDryRun(); try {
else if (!preprocessed.isEmpty()) res.setAdvertisedRefs(transport.getURI(), connection
connection.push(monitor, preprocessed); .getRefsMap());
res.setRemoteUpdates(toPush);
monitor.endTask();
final Map<String, RemoteRefUpdate> preprocessed = prepareRemoteUpdates();
if (transport.isDryRun())
modifyUpdatesForDryRun();
else if (!preprocessed.isEmpty())
connection.push(monitor, preprocessed);
} finally {
connection.close();
res.addMessages(connection.getMessages());
}
if (!transport.isDryRun())
updateTrackingRefs();
for (final RemoteRefUpdate rru : toPush.values()) {
final TrackingRefUpdate tru = rru.getTrackingRefUpdate();
if (tru != null)
res.add(tru);
}
return res;
} finally { } finally {
connection.close(); walker.release();
res.addMessages(connection.getMessages());
} }
if (!transport.isDryRun())
updateTrackingRefs();
for (final RemoteRefUpdate rru : toPush.values()) {
final TrackingRefUpdate tru = rru.getTrackingRefUpdate();
if (tru != null)
res.add(tru);
}
return res;
} }
private Map<String, RemoteRefUpdate> prepareRemoteUpdates() private Map<String, RemoteRefUpdate> prepareRemoteUpdates()

View File

@ -574,6 +574,7 @@ public void receive(final InputStream input, final OutputStream output,
service(); service();
} finally { } finally {
walk.release();
try { try {
if (pckOut != null) if (pckOut != null)
pckOut.flush(); pckOut.flush();

View File

@ -296,6 +296,7 @@ public void upload(final InputStream input, final OutputStream output,
pckOut = new PacketLineOut(rawOut); pckOut = new PacketLineOut(rawOut);
service(); service();
} finally { } finally {
walk.release();
if (timer != null) { if (timer != null) {
try { try {
timer.terminate(); timer.terminate();
@ -567,7 +568,7 @@ private void sendPack() throws IOException {
SideBandOutputStream.CH_PROGRESS, bufsz, rawOut)); SideBandOutputStream.CH_PROGRESS, bufsz, rawOut));
} }
final PackWriter pw = new PackWriter(db); final PackWriter pw = new PackWriter(db, walk.getObjectReader());
try { try {
pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA)); pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
pw.setThin(thin); pw.setThin(thin);