Ensure ObjectReader used by PackWriter is released
The ObjectReader API demands that we release the reader when we are
done with it. PackWriter contains a reader, which it uses for the
entire packing session. Expose the release of the reader through
a release method on the writer.
This still doesn't address the RevWalk and TreeWalk users, who
don't correctly release their reader. But its a small step in the
right direction.
Change-Id: I5cb0b5c1b432434a799fceb21b86479e09b84a0a
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index 18275ec..5b0e74c 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -600,33 +600,38 @@ private static void assertHash(RevObject id, byte[] bin) {
public void packAndPrune() throws Exception {
if (db.getObjectDatabase() instanceof ObjectDirectory) {
ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
+
+ final File pack, idx;
PackWriter pw = new PackWriter(db, NullProgressMonitor.INSTANCE);
-
- Set<ObjectId> all = new HashSet<ObjectId>();
- for (Ref r : db.getAllRefs().values())
- all.add(r.getObjectId());
- pw.preparePack(all, Collections.<ObjectId> emptySet());
-
- final ObjectId name = pw.computeName();
- OutputStream out;
-
- final File pack = nameFor(odb, name, ".pack");
- out = new BufferedOutputStream(new FileOutputStream(pack));
try {
- pw.writePack(out);
- } finally {
- out.close();
- }
- pack.setReadOnly();
+ Set<ObjectId> all = new HashSet<ObjectId>();
+ for (Ref r : db.getAllRefs().values())
+ all.add(r.getObjectId());
+ pw.preparePack(all, Collections.<ObjectId> emptySet());
- final File idx = nameFor(odb, name, ".idx");
- out = new BufferedOutputStream(new FileOutputStream(idx));
- try {
- pw.writeIndex(out);
+ final ObjectId name = pw.computeName();
+ OutputStream out;
+
+ pack = nameFor(odb, name, ".pack");
+ out = new BufferedOutputStream(new FileOutputStream(pack));
+ try {
+ pw.writePack(out);
+ } finally {
+ out.close();
+ }
+ pack.setReadOnly();
+
+ idx = nameFor(odb, name, ".idx");
+ out = new BufferedOutputStream(new FileOutputStream(idx));
+ try {
+ pw.writeIndex(out);
+ } finally {
+ out.close();
+ }
+ idx.setReadOnly();
} finally {
- out.close();
+ pw.release();
}
- idx.setReadOnly();
odb.openPack(pack, idx);
updateServerInfo();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/ConcurrentRepackTest.java
index 96b1178..d85903c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/ConcurrentRepackTest.java
@@ -138,6 +138,7 @@ public void testObjectMovedWithinPack()
pw.addObject(o2);
pw.addObject(o1);
write(out1, pw);
+ pw.release();
// Try the old name, then the new name. The old name should cause the
// pack to reload when it opens and the index and pack mismatch.
@@ -208,6 +209,7 @@ private RevObject parse(final AnyObjectId id)
final File idxFile = fullPackFileName(name, ".idx");
final File[] files = new File[] { packFile, idxFile };
write(files, pw);
+ pw.release();
return files;
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackWriterTest.java
index b12359c..19eec5f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/PackWriterTest.java
@@ -484,6 +484,7 @@ private void createVerifyOpenPack(final Collection<ObjectId> interestings,
writer.setIgnoreMissingUninteresting(ignoreMissingUninteresting);
writer.preparePack(interestings, uninterestings);
writer.writePack(os);
+ writer.release();
verifyOpenPack(thin);
}
@@ -491,6 +492,7 @@ private void createVerifyOpenPack(final Iterator<RevObject> objectSource)
throws MissingObjectException, IOException {
writer.preparePack(objectSource);
writer.writePack(os);
+ writer.release();
verifyOpenPack(false);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
index a716845..cf6e382 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
@@ -610,22 +610,24 @@ private List<ObjectToPack> sortByName() {
* stream.
*/
public void writePack(OutputStream packStream) throws IOException {
- try {
- if ((reuseDeltas || reuseObjects) && reuseSupport != null)
- searchForReuse();
+ if ((reuseDeltas || reuseObjects) && reuseSupport != null)
+ searchForReuse();
- out = new PackOutputStream(packStream, isDeltaBaseAsOffset());
+ out = new PackOutputStream(packStream, isDeltaBaseAsOffset());
- int cnt = getObjectsNumber();
- writeMonitor.beginTask(WRITING_OBJECTS_PROGRESS, cnt);
- out.writeFileHeader(PACK_VERSION_GENERATED, cnt);
- writeObjects();
- writeChecksum();
- writeMonitor.endTask();
- } finally {
- out = null;
- reader.release();
- }
+ writeMonitor.beginTask(WRITING_OBJECTS_PROGRESS, getObjectsNumber());
+ out.writeFileHeader(PACK_VERSION_GENERATED, getObjectsNumber());
+ writeObjects();
+ writeChecksum();
+
+ out = null;
+ reader.release();
+ writeMonitor.endTask();
+ }
+
+ /** Release all resources used by this writer. */
+ public void release() {
+ reader.release();
}
private void searchForReuse() throws IOException {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 72460c9..d1f7bfc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -48,6 +48,7 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
import org.eclipse.jgit.JGitText;
@@ -226,25 +227,29 @@ private String enableCapabilities(final ProgressMonitor monitor) {
private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
final ProgressMonitor monitor) throws IOException {
+ List<ObjectId> remoteObjects = new ArrayList<ObjectId>(getRefs().size());
+ List<ObjectId> newObjects = new ArrayList<ObjectId>(refUpdates.size());
+
+ final long start;
final PackWriter writer = new PackWriter(local, monitor);
- final ArrayList<ObjectId> remoteObjects = new ArrayList<ObjectId>(
- getRefs().size());
- final ArrayList<ObjectId> newObjects = new ArrayList<ObjectId>(
- refUpdates.size());
+ try {
- for (final Ref r : getRefs())
- remoteObjects.add(r.getObjectId());
- remoteObjects.addAll(additionalHaves);
- for (final RemoteRefUpdate r : refUpdates.values()) {
- if (!ObjectId.zeroId().equals(r.getNewObjectId()))
- newObjects.add(r.getNewObjectId());
+ for (final Ref r : getRefs())
+ remoteObjects.add(r.getObjectId());
+ remoteObjects.addAll(additionalHaves);
+ for (final RemoteRefUpdate r : refUpdates.values()) {
+ if (!ObjectId.zeroId().equals(r.getNewObjectId()))
+ newObjects.add(r.getNewObjectId());
+ }
+
+ writer.setThin(thinPack);
+ writer.setDeltaBaseAsOffset(capableOfsDelta);
+ writer.preparePack(newObjects, remoteObjects);
+ start = System.currentTimeMillis();
+ writer.writePack(out);
+ } finally {
+ writer.release();
}
-
- writer.setThin(thinPack);
- writer.setDeltaBaseAsOffset(capableOfsDelta);
- writer.preparePack(newObjects, remoteObjects);
- final long start = System.currentTimeMillis();
- writer.writePack(out);
out.flush();
packTransferTime = System.currentTimeMillis() - start;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
index c5e9baa..71d58e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BundleWriter.java
@@ -165,37 +165,41 @@ public void assume(final RevCommit c) {
* stream.
*/
public void writeBundle(OutputStream os) throws IOException {
- final HashSet<ObjectId> inc = new HashSet<ObjectId>();
- final HashSet<ObjectId> exc = new HashSet<ObjectId>();
- inc.addAll(include.values());
- for (final RevCommit r : assume)
- exc.add(r.getId());
- packWriter.setThin(exc.size() > 0);
- packWriter.preparePack(inc, exc);
+ try {
+ final HashSet<ObjectId> inc = new HashSet<ObjectId>();
+ final HashSet<ObjectId> exc = new HashSet<ObjectId>();
+ inc.addAll(include.values());
+ for (final RevCommit r : assume)
+ exc.add(r.getId());
+ packWriter.setThin(exc.size() > 0);
+ packWriter.preparePack(inc, exc);
- final Writer w = new OutputStreamWriter(os, Constants.CHARSET);
- w.write(TransportBundle.V2_BUNDLE_SIGNATURE);
- w.write('\n');
+ final Writer w = new OutputStreamWriter(os, Constants.CHARSET);
+ w.write(TransportBundle.V2_BUNDLE_SIGNATURE);
+ w.write('\n');
- final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
- for (final RevCommit a : assume) {
- w.write('-');
- a.copyTo(tmp, w);
- if (a.getRawBuffer() != null) {
- w.write(' ');
- w.write(a.getShortMessage());
+ final char[] tmp = new char[Constants.OBJECT_ID_STRING_LENGTH];
+ for (final RevCommit a : assume) {
+ w.write('-');
+ a.copyTo(tmp, w);
+ if (a.getRawBuffer() != null) {
+ w.write(' ');
+ w.write(a.getShortMessage());
+ }
+ w.write('\n');
}
- w.write('\n');
- }
- for (final Map.Entry<String, ObjectId> e : include.entrySet()) {
- e.getValue().copyTo(tmp, w);
- w.write(' ');
- w.write(e.getKey());
- w.write('\n');
- }
+ for (final Map.Entry<String, ObjectId> e : include.entrySet()) {
+ e.getValue().copyTo(tmp, w);
+ w.write(' ');
+ w.write(e.getKey());
+ w.write('\n');
+ }
- w.write('\n');
- w.flush();
- packWriter.writePack(os);
+ w.write('\n');
+ w.flush();
+ packWriter.writePack(os);
+ } finally {
+ packWriter.release();
+ }
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 17c37cf..dfb4168 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -569,25 +569,29 @@ private void sendPack() throws IOException {
final PackWriter pw;
pw = new PackWriter(db, pm, NullProgressMonitor.INSTANCE);
- pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
- pw.setThin(thin);
- pw.preparePack(wantAll, commonBase);
- if (options.contains(OPTION_INCLUDE_TAG)) {
- for (final Ref r : refs.values()) {
- final RevObject o;
- try {
- o = walk.parseAny(r.getObjectId());
- } catch (IOException e) {
- continue;
+ try {
+ pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
+ pw.setThin(thin);
+ pw.preparePack(wantAll, commonBase);
+ if (options.contains(OPTION_INCLUDE_TAG)) {
+ for (final Ref r : refs.values()) {
+ final RevObject o;
+ try {
+ o = walk.parseAny(r.getObjectId());
+ } catch (IOException e) {
+ continue;
+ }
+ if (o.has(WANT) || !(o instanceof RevTag))
+ continue;
+ final RevTag t = (RevTag) o;
+ if (!pw.willInclude(t) && pw.willInclude(t.getObject()))
+ pw.addObject(t);
}
- if (o.has(WANT) || !(o instanceof RevTag))
- continue;
- final RevTag t = (RevTag) o;
- if (!pw.willInclude(t) && pw.willInclude(t.getObject()))
- pw.addObject(t);
}
+ pw.writePack(packOut);
+ } finally {
+ pw.release();
}
- pw.writePack(packOut);
packOut.flush();
if (sideband)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index 1ab6081..a9f9d60 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -209,8 +209,8 @@ private void sendpack(final List<RemoteRefUpdate> updates,
String pathPack = null;
String pathIdx = null;
+ final PackWriter pw = new PackWriter(local, monitor);
try {
- final PackWriter pw = new PackWriter(local, monitor);
final List<ObjectId> need = new ArrayList<ObjectId>();
final List<ObjectId> have = new ArrayList<ObjectId>();
for (final RemoteRefUpdate r : updates)
@@ -281,6 +281,8 @@ private void sendpack(final List<RemoteRefUpdate> updates,
safeDelete(pathPack);
throw new TransportException(uri, JGitText.get().cannotStoreObjects, err);
+ } finally {
+ pw.release();
}
}