Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[jgit-dev] Making RevCommit object representation more compact in memory

I was browsing through JGit source code and noticed that it strives to
be fast and efficient, preserving every byte where possible. I
appreciate this approach and I think it could be optimized even
further. So I want to share and discuss my idea with the community.

Every RevCommit object has array of parent commits, though most of the
time the array will contain only one element, as most of the commits
have single parent. The idea is simple: lets declare the parents field
of type Object, that will either:

  1. Point to a single parent RevCommit object, or
  2. Will contain array of parents, if there are many of them.

This way it will allocate arrays for only those commits that really need it.
Sure it will require more CPU cycles to access parents then, but CPU
cycles are cheap these days, memory access is not.

Let me show you a short piece of code to sketch out the idea:

  public class RevCommit extends RevObject {
      ...
      /** Either single parent commit or array of parent commits
       *  if there are many of them. */
      Object parents;
      ...
      public final int getParentCount() {
          if (parents instanceof RevCommit)
              return 1;
          return ((RevCommit[]) parents).length;
      }

      public final RevCommit getParent(final int nth) {
          if (nth > 0)
              return ((RevCommit[]) parents)[nth];
          if (parents instanceof RevCommit)
              return (RevCommit) parents;
          return ((RevCommit[]) parents)[0];
      }

      public final RevCommit[] getParents() {
          if (parents instanceof RevCommit)
              return new RevCommit[]{(RevCommit) parents};
          return (RevCommit[]) parents;
      }

In fact I have already implemented it in my local copy of JGit,
everything seems to work just fine, and I am attaching a patch for
your to play with. There are few places in question, though, such as
RewriteTreeFilter and RewriteGenerator. These classes manipulate
parents array directly, and I'm afraid of modifying them as I don't
understand what they do.

If you think it is worth making changes into JGit please feel free to
contact me with further instructions on how to apply this patch. Or
you make it yourself.

Cheers,
Alex
Index: org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommitList.java	(revision )
@@ -44,16 +44,16 @@
 
 package org.eclipse.jgit.revplot;
 
+import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.revwalk.RevCommitList;
+import org.eclipse.jgit.revwalk.RevWalk;
+
 import java.text.MessageFormat;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.TreeSet;
 
-import org.eclipse.jgit.JGitText;
-import org.eclipse.jgit.revwalk.RevCommitList;
-import org.eclipse.jgit.revwalk.RevWalk;
-
 /**
  * An ordered list of {@link PlotCommit} subclasses.
  * <p>
@@ -122,11 +122,11 @@
 		if (nChildren == 0)
 			return;
 
-		if (nChildren == 1 && currCommit.children[0].getParentCount() < 2) {
+		if (nChildren == 1 && currCommit.getChild(0).getParentCount() < 2) {
 			// Only one child, child has only us as their parent.
 			// Stay in the same lane as the child.
 			//
-			final PlotCommit c = currCommit.children[0];
+			final PlotCommit c = currCommit.getChild(0);
 			if (c.lane == null) {
 				// Hmmph. This child must be the first along this lane.
 				//
@@ -165,7 +165,7 @@
 			PlotLane reservedLane = null;
 
 			for (int i = 0; i < nChildren; i++) {
-				final PlotCommit c = currCommit.children[i];
+				final PlotCommit c = currCommit.getChild(i);
 				// don't forget to position all of your children if they are
 				// not already positioned.
 				if (c.lane == null) {
Index: org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java	(revision )
@@ -44,50 +44,26 @@
 
 package org.eclipse.jgit.transport;
 
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.errors.CompoundException;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.TransportException;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.FileMode;
-import org.eclipse.jgit.lib.MutableObjectId;
-import org.eclipse.jgit.lib.ObjectChecker;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.lib.ProgressMonitor;
-import org.eclipse.jgit.lib.Ref;
-import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.DateRevQueue;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.revwalk.RevFlag;
-import org.eclipse.jgit.revwalk.RevObject;
-import org.eclipse.jgit.revwalk.RevTag;
-import org.eclipse.jgit.revwalk.RevTree;
-import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.lib.*;
+import org.eclipse.jgit.revwalk.*;
 import org.eclipse.jgit.storage.file.ObjectDirectory;
 import org.eclipse.jgit.storage.file.PackIndex;
 import org.eclipse.jgit.storage.file.PackLock;
 import org.eclipse.jgit.storage.file.UnpackedObject;
 import org.eclipse.jgit.treewalk.TreeWalk;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.*;
+
 /**
  * Generic fetch support for dumb transport protocols.
  * <p>
@@ -366,8 +342,9 @@
 		final RevCommit commit = (RevCommit) obj;
 		markLocalCommitsComplete(commit.getCommitTime());
 		needs(commit.getTree());
-		for (final RevCommit p : commit.getParents())
-			needs(p);
+		final int nParents = commit.getParentCount();
+		for (int i = 0; i < nParents; i++)
+			needs(commit.getParent(i));
 		obj.add(COMPLETE);
 	}
 
@@ -707,8 +684,9 @@
 				localCommitQueue.next();
 
 				markTreeComplete(c.getTree());
-				for (final RevCommit p : c.getParents())
-					pushLocalCommit(p);
+				final int nParents = c.getParentCount();
+				for (int i = 0; i < nParents; i++)
+					pushLocalCommit(c.getParent(i));
 			}
 		} catch (IOException err) {
 			throw new TransportException(JGitText.get().localObjectsIncomplete, err);
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/AbstractRevQueue.java	(revision )
@@ -95,12 +95,12 @@
 	 *            flag that controls admission to the queue.
 	 */
 	public final void addParents(final RevCommit c, final RevFlag queueControl) {
-		final RevCommit[] pList = c.parents;
-		if (pList == null)
-			return;
-		for (RevCommit p : pList)
+		final int nParents = c.getParentCount();
+		for (int i = 0; i < nParents; i++) {
+			final RevCommit p = c.getParent(i);
 			add(p, queueControl);
-	}
+		}
+	}
 
 	/**
 	 * Remove the first commit from the queue.
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java	(revision )
@@ -44,32 +44,16 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.List;
-
 import org.eclipse.jgit.JGitText;
-import org.eclipse.jgit.errors.CorruptObjectException;
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.LargeObjectException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.errors.RevWalkException;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.MutableObjectId;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectIdSubclassMap;
-import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.errors.*;
+import org.eclipse.jgit.lib.*;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.*;
+
 /**
  * Walks a commit graph and produces the matching commits in order.
  * <p>
@@ -1170,9 +1154,9 @@
 			final RevCommit c = q.next();
 			if (c == null)
 				break;
-			if (c.parents == null)
-				continue;
-			for (final RevCommit p : c.parents) {
+			final int nParents = c.getParentCount();
+			for (int i = 0; i < nParents; i++) {
+				final RevCommit p = c.getParent(i);
 				if ((p.flags & clearFlags) == 0)
 					continue;
 				p.flags &= retainFlags;
Index: org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
===================================================================
--- org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java	(revision )
@@ -43,17 +43,12 @@
 
 package org.eclipse.jgit.revwalk;
 
+import org.eclipse.jgit.lib.*;
+
 import java.io.ByteArrayOutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.TimeZone;
 
-import org.eclipse.jgit.lib.CommitBuilder;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.lib.RepositoryTestCase;
-
 public class RevCommitParseTest extends RepositoryTestCase {
 	public void testParse_NoParents() throws Exception {
 		final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
@@ -107,7 +102,7 @@
 		assertSame(rw.lookupTree(treeId), c.getTree());
 
 		assertNotNull(c.parents);
-		assertEquals(0, c.parents.length);
+		assertEquals(0, c.getParentCount());
 		assertEquals("", c.getFullMessage());
 
 		final PersonIdent cAuthor = c.getAuthorIdent();
@@ -125,6 +120,44 @@
 		assertEquals(TimeZone.getTimeZone("GMT" + committerTimeZone), cCommitter.getTimeZone());
 	}
 
+	public void testParse_MultipleParents() throws Exception {
+		final ObjectId tId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
+		final ObjectId p0Id = id("0000000000000000000000000000000000000001");
+		final ObjectId p1Id = id("0000000000000000000000000000000000000002");
+		final ObjectId p2Id = id("0000000000000000000000000000000000000003");
+
+		final StringBuilder body = new StringBuilder();
+
+		body.append("tree ").append(tId.name()).append("\n");
+		body.append("parent ").append(p0Id.name()).append("\n");
+		body.append("parent ").append(p1Id.name()).append("\n");
+		body.append("parent ").append(p2Id.name()).append("\n");
+		body.append("author A U. Thor <a_u_thor@xxxxxxxxxxx> 1218123387 +0700\n");
+		body.append("committer C O. Miter <c@xxxxxxxxxxx> 1218123390 -0500\n");
+
+		body.append("\n");
+
+		final RevWalk rw = new RevWalk(db);
+		final RevCommit c;
+
+		c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+		assertNull(c.getTree());
+		assertNull(c.parents);
+
+		c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+
+		assertNotNull(c.getTree());
+		assertEquals(tId, c.getTree().getId());
+
+		assertNotNull(c.parents);
+		assertEquals(3, c.getParentCount());
+		assertEquals(p0Id, c.getParent(0));
+		assertEquals(p1Id, c.getParent(1));
+		assertEquals(p2Id, c.getParent(2));
+
+		assertEquals("", c.getFullMessage());
+	}
+
 	private RevCommit create(final String msg) throws Exception {
 		final StringBuilder b = new StringBuilder();
 		b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteTreeFilter.java	(revision )
@@ -43,12 +43,9 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-import java.util.List;
-
 import org.eclipse.jgit.diff.DiffEntry;
-import org.eclipse.jgit.diff.RenameDetector;
 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.diff.RenameDetector;
 import org.eclipse.jgit.errors.CorruptObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
@@ -59,6 +56,9 @@
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 
+import java.io.IOException;
+import java.util.List;
+
 /**
  * First phase of a path limited revision walk.
  * <p>
@@ -102,12 +102,12 @@
 			IncorrectObjectTypeException, IOException {
 		// Reset the tree filter to scan this commit and parents.
 		//
-		final RevCommit[] pList = c.parents;
+		final RevCommit[] pList = c.getParents();
 		final int nParents = pList.length;
 		final TreeWalk tw = pathFilter;
 		final ObjectId[] trees = new ObjectId[nParents + 1];
 		for (int i = 0; i < nParents; i++) {
-			final RevCommit p = c.parents[i];
+			final RevCommit p = pList[i];
 			if ((p.flags & PARSED) == 0)
 				p.parseHeaders(walker);
 			trees[i] = p.getTree();
@@ -196,7 +196,7 @@
 				}
 
 				c.flags |= REWRITE;
-				c.parents = new RevCommit[] { p };
+				c.parents = p; // Single parent.
 				return false;
 			}
 
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/TopoSortGenerator.java	(revision )
@@ -43,11 +43,11 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
+import java.io.IOException;
+
 /** Sorts commits in topological order. */
 class TopoSortGenerator extends Generator {
 	private static final int TOPO_DELAY = RevWalk.TOPO_DELAY;
@@ -78,8 +78,11 @@
 			final RevCommit c = s.next();
 			if (c == null)
 				break;
-			for (final RevCommit p : c.parents)
+			final int nParents = c.getParentCount();
+			for (int i = 0; i < nParents; i++) {
+				final RevCommit p = c.getParent(i);
 				p.inDegree++;
+			}
 			pending.add(c);
 		}
 	}
@@ -113,7 +116,9 @@
 			// All of our children have already produced,
 			// so it is OK for us to produce now as well.
 			//
-			for (final RevCommit p : c.parents) {
+			final int nParents = c.getParentCount();
+			for (int i = 0; i < nParents; i++) {
+				final RevCommit p = c.getParent(i);
 				if (--p.inDegree == 0 && (p.flags & TOPO_DELAY) != 0) {
 					// This parent tried to come before us, but we are
 					// his last child. unpop the parent so it goes right
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevCommit.java	(revision )
@@ -44,22 +44,17 @@
 
 package org.eclipse.jgit.revwalk;
 
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.*;
+import org.eclipse.jgit.util.RawParseUtils;
+
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.eclipse.jgit.errors.IncorrectObjectTypeException;
-import org.eclipse.jgit.errors.MissingObjectException;
-import org.eclipse.jgit.lib.AnyObjectId;
-import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.MutableObjectId;
-import org.eclipse.jgit.lib.ObjectInserter;
-import org.eclipse.jgit.lib.ObjectReader;
-import org.eclipse.jgit.lib.PersonIdent;
-import org.eclipse.jgit.util.RawParseUtils;
-
 /** A commit reference to a commit in the DAG. */
 public class RevCommit extends RevObject {
 	/**
@@ -112,7 +107,7 @@
 
 	private RevTree tree;
 
-	RevCommit[] parents;
+	Object parents;
 
 	int commitTime; // An int here for performance, overflows in 2038
 
@@ -153,33 +148,28 @@
 
 		int ptr = 46;
 		if (parents == null) {
-			RevCommit[] pList = new RevCommit[1];
+			Object pList = NO_PARENTS;
 			int nParents = 0;
 			for (;;) {
 				if (raw[ptr] != 'p')
 					break;
 				idBuffer.fromString(raw, ptr + 7);
 				final RevCommit p = walk.lookupCommit(idBuffer);
-				if (nParents == 0)
-					pList[nParents++] = p;
-				else if (nParents == 1) {
-					pList = new RevCommit[] { pList[0], p };
+				if (nParents == 0) {
+					pList = p;
+					nParents = 1;
+				} else if (nParents == 1) {
+					pList = new RevCommit[] { (RevCommit) pList, p };
 					nParents = 2;
 				} else {
-					if (pList.length <= nParents) {
-						RevCommit[] old = pList;
-						pList = new RevCommit[pList.length + 32];
-						System.arraycopy(old, 0, pList, 0, nParents);
+					final RevCommit[] tmp = new RevCommit[nParents + 1];
+					System.arraycopy((RevCommit[]) pList, 0, tmp, 0, nParents);
+					tmp[nParents] = p;
+					pList = tmp;
+					nParents++;
-					}
+				}
-					pList[nParents++] = p;
-				}
 				ptr += 48;
 			}
-			if (nParents != pList.length) {
-				RevCommit[] old = pList;
-				pList = new RevCommit[nParents];
-				System.arraycopy(old, 0, pList, 0, nParents);
-			}
 			parents = pList;
 		}
 
@@ -204,22 +194,19 @@
 
 	static void carryFlags(RevCommit c, final int carry) {
 		for (;;) {
-			final RevCommit[] pList = c.parents;
-			if (pList == null)
+			final int nParents = c.getParentCount();
+			if (nParents == 0)
 				return;
-			final int n = pList.length;
-			if (n == 0)
-				return;
 
-			for (int i = 1; i < n; i++) {
-				final RevCommit p = pList[i];
+			for (int i = 1; i < nParents; i++) {
+				final RevCommit p = c.getParent(i);
 				if ((p.flags & carry) == carry)
 					continue;
 				p.flags |= carry;
 				carryFlags(p, carry);
 			}
 
-			c = pList[0];
+			c = c.getParent(0);
 			if ((c.flags & carry) == carry)
 				return;
 			c.flags |= carry;
@@ -268,7 +255,9 @@
 	 * @return number of parents; always a positive value but can be 0.
 	 */
 	public final int getParentCount() {
-		return parents.length;
+		if (parents instanceof RevCommit)
+			return 1;
+		return ((RevCommit[]) parents).length;
 	}
 
 	/**
@@ -282,12 +271,20 @@
 	 *             an invalid parent index was specified.
 	 */
 	public final RevCommit getParent(final int nth) {
-		return parents[nth];
+		if (nth > 0)
+			return ((RevCommit[]) parents)[nth];
+		if (parents instanceof RevCommit)
+			return (RevCommit) parents;
+		return ((RevCommit[]) parents)[0];
 	}
 
 	/**
-	 * Obtain an array of all parents (<b>NOTE - THIS IS NOT A COPY</b>).
+	 * Obtain an array of all parents (<b>NOTE - THIS IS NOT ALWAYS A COPY</b>).
 	 * <p>
+	 * If this commit has single parent, a new array with this parent as a sole
+	 * elements will be returned. Otherwise, the internal array of parents will
+	 * be returned.
+	 * <p>
 	 * This method is exposed only to provide very fast, efficient access to
 	 * this commit's parent list. Applications relying on this list should be
 	 * very careful to ensure they do not modify its contents during their use
@@ -296,7 +293,9 @@
 	 * @return the array of parents.
 	 */
 	public final RevCommit[] getParents() {
-		return parents;
+		if (parents instanceof RevCommit)
+			return new RevCommit[]{(RevCommit) parents};
+		return (RevCommit[]) parents;
 	}
 
 	/**
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/PendingGenerator.java	(revision )
@@ -44,14 +44,14 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StopWalkException;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.revwalk.filter.RevFilter;
 
+import java.io.IOException;
+
 /**
  * Default (and first pass) RevCommit Generator implementation for RevWalk.
  * <p>
@@ -140,7 +140,9 @@
 				else
 					produce = filter.include(walker, c);
 
-				for (final RevCommit p : c.parents) {
+				final int nParents = c.getParentCount();
+				for (int i = 0; i < nParents; i++) {
+					final RevCommit p = c.getParent(i);
 					if ((p.flags & SEEN) != 0)
 						continue;
 					if ((p.flags & PARSED) == 0)
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RewriteGenerator.java	(revision )
@@ -43,11 +43,11 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
+import java.io.IOException;
+
 /**
  * Replaces a RevCommit's parents until not colored with REWRITE.
  * <p>
@@ -99,7 +99,7 @@
 				return null;
 
 			boolean rewrote = false;
-			final RevCommit[] pList = c.parents;
+			final RevCommit[] pList = c.getParents();
 			final int nParents = pList.length;
 			for (int i = 0; i < nParents; i++) {
 				final RevCommit oldp = pList[i];
@@ -118,7 +118,7 @@
 
 	private RevCommit rewrite(RevCommit p) {
 		for (;;) {
-			final RevCommit[] pList = p.parents;
+			final RevCommit[] pList = p.getParents();
 			if (pList.length > 1) {
 				// This parent is a merge, so keep it.
 				//
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/BoundaryGenerator.java	(revision )
@@ -44,11 +44,11 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
+import java.io.IOException;
+
 class BoundaryGenerator extends Generator {
 	static final int UNINTERESTING = RevWalk.UNINTERESTING;
 
@@ -107,9 +107,12 @@
 				IncorrectObjectTypeException, IOException {
 			RevCommit c = source.next();
 			if (c != null) {
-				for (final RevCommit p : c.parents)
+				final int nParents = c.getParentCount();
+				for (int i = 0; i < nParents; i++) {
+					final RevCommit p = c.getParent(i);
 					if ((p.flags & UNINTERESTING) != 0)
 						held.add(p);
+				}
 				return c;
 			}
 
Index: org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revwalk/MergeBaseGenerator.java	(revision )
@@ -43,13 +43,13 @@
 
 package org.eclipse.jgit.revwalk;
 
-import java.io.IOException;
-import java.text.MessageFormat;
-
 import org.eclipse.jgit.JGitText;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 
+import java.io.IOException;
+import java.text.MessageFormat;
+
 /**
  * Computes the merge base(s) of the starting commits.
  * <p>
@@ -142,7 +142,9 @@
 				return null;
 			}
 
-			for (final RevCommit p : c.parents) {
+			final int nParents = c.getParentCount();
+			for (int i = 0; i < nParents; i++) {
+				final RevCommit p = c.getParent(i);
 				if ((p.flags & IN_PENDING) != 0)
 					continue;
 				if ((p.flags & PARSED) == 0)
@@ -183,20 +185,17 @@
 
 	private void carryOntoHistory(RevCommit c, final int carry) {
 		for (;;) {
-			final RevCommit[] pList = c.parents;
-			if (pList == null)
-				return;
-			final int n = pList.length;
+			final int n = c.getParentCount();
 			if (n == 0)
 				return;
 
 			for (int i = 1; i < n; i++) {
-				final RevCommit p = pList[i];
+				final RevCommit p = c.getParent(i);
 				if (!carryOntoOne(p, carry))
 					carryOntoHistory(p, carry);
 			}
 
-			c = pList[0];
+			c = c.getParent(0);
 			if (carryOntoOne(c, carry))
 				break;
 		}
Index: org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java
===================================================================
--- org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java	(revision 2160c09dd4f678c5f2f8e730945be637210b39de)
+++ org.eclipse.jgit/src/org/eclipse/jgit/revplot/PlotCommit.java	(revision )
@@ -63,7 +63,7 @@
 
 	PlotLane lane;
 
-	PlotCommit[] children;
+	Object children;
 
 	Ref[] refs;
 
@@ -94,26 +94,36 @@
 	}
 
 	void addChild(final PlotCommit c) {
-		final int cnt = children.length;
+		if (children == NO_CHILDREN)
+			children = c;
+		else if (children instanceof PlotCommit)
+			children = new PlotCommit[]{((PlotCommit) children), c};
+		else {
+			PlotCommit[] array = (PlotCommit[]) children;
+			final int cnt = array.length;
-		if (cnt == 0)
+			if (cnt == 0)
-			children = new PlotCommit[] { c };
+				children = new PlotCommit[]{c};
-		else if (cnt == 1)
+			else if (cnt == 1)
-			children = new PlotCommit[] { children[0], c };
+				children = new PlotCommit[]{array[0], c};
-		else {
-			final PlotCommit[] n = new PlotCommit[cnt + 1];
+			else {
+				final PlotCommit[] n = new PlotCommit[cnt + 1];
-			System.arraycopy(children, 0, n, 0, cnt);
+				System.arraycopy(array, 0, n, 0, cnt);
-			n[cnt] = c;
-			children = n;
-		}
-	}
+				n[cnt] = c;
+				children = n;
+			}
+		}
 
+	}
+
 	/**
 	 * Get the number of child commits listed in this commit.
 	 *
 	 * @return number of children; always a positive value but can be 0.
 	 */
 	public final int getChildCount() {
-		return children.length;
+		if (children instanceof RevCommit)
+			return 1;
+		return ((PlotCommit[]) children).length;
 	}
 
 	/**
@@ -127,7 +137,11 @@
 	 *             an invalid child index was specified.
 	 */
 	public final PlotCommit getChild(final int nth) {
-		return children[nth];
+		if (nth > 0)
+			return ((PlotCommit[]) children)[nth];
+		if (children instanceof RevCommit)
+			return (PlotCommit) children;
+		return ((PlotCommit[]) children)[0];
 	}
 
 	/**
@@ -138,7 +152,9 @@
 	 * @return true if the given commit built on top of this commit.
 	 */
 	public final boolean isChild(final PlotCommit c) {
-		for (final PlotCommit a : children)
+		if (children instanceof PlotCommit)
+			return children == c;
+		for (final PlotCommit a : (PlotCommit[]) children)
 			if (a == c)
 				return true;
 		return false;

Back to the top