From 761814fe9c3fc0503d4654ef4aace6a804da5ae7 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Sat, 28 Nov 2015 08:58:15 -0800 Subject: [PATCH] DirCacheEntry: Speed up creation by avoiding string cast The checkPath function is available as a byte[] form, in fact the String form just converts to byte[] to run the algorithm. Having DirCacheEntry take a byte[] -> String -> byte[] to check if each path is valid is a huge waste of CPU time. On some systems it can double the time required to read 38,999 files from trees to the DirCache. This slows down any operation using a DirCache. Expose the byte[] form and use it for DirCacheEntry creation. Change-Id: I6db7bc793ece99ff3c356338d793c07c061aeac7 --- .../jgit/dircache/DirCacheEntryTest.java | 4 ++-- .../jgit/dircache/DirCacheCheckout.java | 18 --------------- .../eclipse/jgit/dircache/DirCacheEntry.java | 23 ++++++++++++++----- .../org/eclipse/jgit/util/SystemReader.java | 15 ++++++++++++ 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java index e159ed939..dc7181aec 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheEntryTest.java @@ -69,9 +69,9 @@ public class DirCacheEntryTest { assertFalse(isValidPath("a\u0000b")); } - private static boolean isValidPath(final String path) { + private static boolean isValidPath(String path) { try { - DirCacheCheckout.checkValidPath(path); + new DirCacheEntry(path); return true; } catch (InvalidPathException e) { return false; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java index 393a85494..4eb688170 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java @@ -1342,24 +1342,6 @@ public class DirCacheCheckout { checkValidPathSegment(chk, i); } - /** - * Check if path is a valid path for a checked out file name or ref name. - * - * @param path - * @throws InvalidPathException - * if the path is invalid - * @since 3.3 - */ - static void checkValidPath(String path) throws InvalidPathException { - try { - SystemReader.getInstance().checkPath(path); - } catch (CorruptObjectException e) { - InvalidPathException p = new InvalidPathException(path); - p.initCause(e); - throw p; - } - } - private static void checkValidPathSegment(ObjectChecker chk, CanonicalTreeParser t) throws InvalidPathException { try { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java index eef2e6d3c..404ff1738 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheEntry.java @@ -65,6 +65,7 @@ import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.MutableInteger; import org.eclipse.jgit.util.NB; +import org.eclipse.jgit.util.SystemReader; /** * A single file (or stage of a file) in a {@link DirCache}. @@ -191,7 +192,7 @@ public class DirCacheEntry { } try { - DirCacheCheckout.checkValidPath(toString(path)); + checkPath(path); } catch (InvalidPathException e) { CorruptObjectException p = new CorruptObjectException(e.getMessage()); @@ -263,7 +264,7 @@ public class DirCacheEntry { /** * Create an empty entry at the specified stage. * - * @param newPath + * @param path * name of the cache entry, in the standard encoding. * @param stage * the stage index of the new entry. @@ -274,16 +275,16 @@ public class DirCacheEntry { * range 0..3, inclusive. */ @SuppressWarnings("boxing") - public DirCacheEntry(final byte[] newPath, final int stage) { - DirCacheCheckout.checkValidPath(toString(newPath)); + public DirCacheEntry(byte[] path, final int stage) { + checkPath(path); if (stage < 0 || 3 < stage) throw new IllegalArgumentException(MessageFormat.format( JGitText.get().invalidStageForPath, - stage, toString(newPath))); + stage, toString(path))); info = new byte[INFO_LEN]; infoOffset = 0; - path = newPath; + this.path = path; int flags = ((stage & 0x3) << 12); if (path.length < NAME_MASK) @@ -730,6 +731,16 @@ public class DirCacheEntry { return 0; } + private static void checkPath(byte[] path) { + try { + SystemReader.getInstance().checkPath(path); + } catch (CorruptObjectException e) { + InvalidPathException p = new InvalidPathException(toString(path)); + p.initCause(e); + throw p; + } + } + private static String toString(final byte[] path) { return Constants.CHARSET.decode(ByteBuffer.wrap(path)).toString(); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java index 4795c89e7..9860ef070 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -339,4 +339,19 @@ public abstract class SystemReader { public void checkPath(String path) throws CorruptObjectException { platformChecker.checkPath(path); } + + /** + * Check tree path entry for validity. + *

+ * Scans a multi-directory path string such as {@code "src/main.c"}. + * + * @param path + * path string to scan. + * @throws CorruptObjectException + * path is invalid. + * @since 4.2 + */ + public void checkPath(byte[] path) throws CorruptObjectException { + platformChecker.checkPath(path, 0, path.length); + } }