]> source.dussan.org Git - jgit.git/commitdiff
Index config section and subsection names in one pass 87/5487/2
authorShawn O. Pearce <spearce@spearce.org>
Tue, 27 Mar 2012 19:32:16 +0000 (15:32 -0400)
committerShawn O. Pearce <spearce@spearce.org>
Mon, 2 Apr 2012 18:44:45 +0000 (11:44 -0700)
Instead of indexing the subsection names on each request for a given
section name, index both the section and subsection names in a single
scan through the entry list. This should improve lookup time for
reading the section names out of the configuration, especially for the
url.*.insteadof type of processing performed in RemoteConfig.

Change-Id: I7b3269565b1308f69d20dc3f3fe917aea00f8a73

org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigSnapshot.java

index b9f62177ccac504653d65d85c3681da6e1ed3b3f..c764928771aab7bbcf9f402c410befef664f1dd3 100644 (file)
@@ -414,9 +414,9 @@ public class ConfigTest {
                                names.contains("repositoryformatversion"));
 
                Iterator<String> itr = names.iterator();
-               assertEquals("repositoryFormatVersion", itr.next());
                assertEquals("filemode", itr.next());
                assertEquals("logAllRefUpdates", itr.next());
+               assertEquals("repositoryFormatVersion", itr.next());
                assertFalse(itr.hasNext());
        }
 
index 58a03bf8bf12bf94aa85b0f7de61ef376b61412d..1619b589c4ddc56aff6a703e01e6aeceb3e3dc82 100644 (file)
 package org.eclipse.jgit.lib;
 
 import java.text.MessageFormat;
-import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -479,17 +474,22 @@ public class Config {
         *            section to search for.
         * @return set of all subsections of specified section within this
         *         configuration and its base configuration; may be empty if no
-        *         subsection exists.
+        *         subsection exists. The set's iterator returns sections in the
+        *         order they are declared by the configuration starting from this
+        *         instance and progressing through the base.
         */
        public Set<String> getSubsections(final String section) {
-               return get(new SubsectionNames(section));
+               return getState().getSubsections(section);
        }
 
        /**
-        * @return the sections defined in this {@link Config}
+        * @return the sections defined in this {@link Config}. The set's iterator
+        *         returns sections in the order they are declared by the
+        *         configuration starting from this instance and progressing through
+        *         the base.
         */
        public Set<String> getSections() {
-               return get(new SectionNames());
+               return getState().getSections();
        }
 
        /**
@@ -509,7 +509,7 @@ public class Config {
         * @return the list of names defined for this subsection
         */
        public Set<String> getNames(String section, String subsection) {
-               return get(new NamesInSection(section, subsection));
+               return getState().getNames(section, subsection);
        }
 
        /**
@@ -1243,144 +1243,6 @@ public class Config {
                T parse(Config cfg);
        }
 
-       private static class SubsectionNames implements SectionParser<Set<String>> {
-               private final String section;
-
-               SubsectionNames(final String sectionName) {
-                       section = sectionName;
-               }
-
-               public int hashCode() {
-                       return section.hashCode();
-               }
-
-               public boolean equals(Object other) {
-                       if (other instanceof SubsectionNames) {
-                               return section.equals(((SubsectionNames) other).section);
-                       }
-                       return false;
-               }
-
-               public Set<String> parse(Config cfg) {
-                       final Set<String> result = new LinkedHashSet<String>();
-                       while (cfg != null) {
-                               for (final ConfigLine e : cfg.state.get().entryList) {
-                                       if (e.subsection != null && e.name == null
-                                                       && StringUtils.equalsIgnoreCase(section, e.section))
-                                               result.add(e.subsection);
-                               }
-                               cfg = cfg.baseConfig;
-                       }
-                       return Collections.unmodifiableSet(result);
-               }
-       }
-
-       private static class NamesInSection implements SectionParser<Set<String>> {
-               private final String section;
-
-               private final String subsection;
-
-               NamesInSection(final String sectionName, final String subSectionName) {
-                       section = sectionName;
-                       subsection = subSectionName;
-               }
-
-               @Override
-               public int hashCode() {
-                       final int prime = 31;
-                       int result = 1;
-                       result = prime * result + section.hashCode();
-                       result = prime * result
-                                       + ((subsection == null) ? 0 : subsection.hashCode());
-                       return result;
-               }
-
-               @Override
-               public boolean equals(Object obj) {
-                       if (this == obj)
-                               return true;
-                       if (obj == null)
-                               return false;
-                       if (getClass() != obj.getClass())
-                               return false;
-                       NamesInSection other = (NamesInSection) obj;
-                       if (!section.equals(other.section))
-                               return false;
-                       if (subsection == null) {
-                               if (other.subsection != null)
-                                       return false;
-                       } else if (!subsection.equals(other.subsection))
-                               return false;
-                       return true;
-               }
-
-               public Set<String> parse(Config cfg) {
-                       final Map<String, String> m = new LinkedHashMap<String, String>();
-                       while (cfg != null) {
-                               for (final ConfigLine e : cfg.state.get().entryList) {
-                                       if (e.name == null)
-                                               continue;
-                                       if (!StringUtils.equalsIgnoreCase(section, e.section))
-                                               continue;
-                                       if ((subsection == null && e.subsection == null)
-                                                       || (subsection != null && subsection
-                                                                       .equals(e.subsection))) {
-                                               String lc = StringUtils.toLowerCase(e.name);
-                                               if (!m.containsKey(lc))
-                                                       m.put(lc, e.name);
-                                       }
-                               }
-                               cfg = cfg.baseConfig;
-                       }
-                       return new CaseFoldingSet(m);
-               }
-       }
-
-       private static class SectionNames implements SectionParser<Set<String>> {
-               public Set<String> parse(Config cfg) {
-                       final Map<String, String> m = new LinkedHashMap<String, String>();
-                       while (cfg != null) {
-                               for (final ConfigLine e : cfg.state.get().entryList) {
-                                       if (e.section != null) {
-                                               String lc = StringUtils.toLowerCase(e.section);
-                                               if (!m.containsKey(lc))
-                                                       m.put(lc, e.section);
-                                       }
-                               }
-                               cfg = cfg.baseConfig;
-                       }
-                       return new CaseFoldingSet(m);
-               }
-       }
-
-       private static class CaseFoldingSet extends AbstractSet<String> {
-               private final Map<String, String> names;
-
-               CaseFoldingSet(Map<String, String> names) {
-                       this.names = Collections.unmodifiableMap(names);
-               }
-
-               @Override
-               public boolean contains(Object needle) {
-                       if (!(needle instanceof String))
-                               return false;
-
-                       String n = (String) needle;
-                       return names.containsKey(n)
-                                       || names.containsKey(StringUtils.toLowerCase(n));
-               }
-
-               @Override
-               public Iterator<String> iterator() {
-                       return names.values().iterator();
-               }
-
-               @Override
-               public int size() {
-                       return names.size();
-               }
-       }
-
        private static class StringReader {
                private final char[] buf;
 
index 5527267b864cd666108b5d55a853806942c4473d..cc5fe25e52320b2a2c37437d68716ed6dc1726fa 100644 (file)
@@ -52,19 +52,29 @@ package org.eclipse.jgit.lib;
 
 import static org.eclipse.jgit.util.StringUtils.compareIgnoreCase;
 import static org.eclipse.jgit.util.StringUtils.compareWithCase;
+import static org.eclipse.jgit.util.StringUtils.toLowerCase;
 
+import java.util.AbstractSet;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.eclipse.jgit.util.StringUtils;
+
 class ConfigSnapshot {
        final List<ConfigLine> entryList;
        final Map<Object, Object> cache;
        final ConfigSnapshot baseState;
        volatile List<ConfigLine> sorted;
+       volatile SectionNames names;
 
        ConfigSnapshot(List<ConfigLine> entries, ConfigSnapshot base) {
                entryList = entries;
@@ -72,6 +82,40 @@ class ConfigSnapshot {
                baseState = base;
        }
 
+       Set<String> getSections() {
+               return names().sections;
+       }
+
+       Set<String> getSubsections(String section) {
+               Map<String, Set<String>> m = names().subsections;
+               Set<String> r = m.get(section);
+               if (r == null)
+                       r = m.get(toLowerCase(section));
+               if (r == null)
+                       return Collections.emptySet();
+               return Collections.unmodifiableSet(r);
+       }
+
+       Set<String> getNames(String section, String subsection) {
+               List<ConfigLine> s = sorted();
+               int idx = find(s, section, subsection, "");
+               if (idx < 0)
+                       idx = -(idx + 1);
+
+               Map<String, String> m = new LinkedHashMap<String, String>();
+               while (idx < s.size()) {
+                       ConfigLine e = s.get(idx++);
+                       if (!e.match(section, subsection))
+                               break;
+                       if (e.name == null)
+                               continue;
+                       String l = toLowerCase(e.name);
+                       if (!m.containsKey(l))
+                               m.put(l, e.name);
+               }
+               return new CaseFoldingSet(m);
+       }
+
        String[] get(String section, String subsection, String name) {
                List<ConfigLine> s = sorted();
                int idx = find(s, section, subsection, name);
@@ -167,4 +211,86 @@ class ConfigSnapshot {
                                        b.section, b.subsection, b.name);
                }
        }
+
+       private SectionNames names() {
+               SectionNames n = names;
+               if (n == null)
+                       names = n = new SectionNames(this);
+               return n;
+       }
+
+       private static class SectionNames {
+               final CaseFoldingSet sections;
+               final Map<String, Set<String>> subsections;
+
+               SectionNames(ConfigSnapshot cfg) {
+                       Map<String, String> sec = new LinkedHashMap<String, String>();
+                       Map<String, Set<String>> sub = new HashMap<String, Set<String>>();
+                       while (cfg != null) {
+                               for (ConfigLine e : cfg.entryList) {
+                                       if (e.section == null)
+                                               continue;
+
+                                       String l1 = toLowerCase(e.section);
+                                       if (!sec.containsKey(l1))
+                                               sec.put(l1, e.section);
+
+                                       if (e.subsection == null)
+                                               continue;
+
+                                       Set<String> m = sub.get(l1);
+                                       if (m == null) {
+                                               m = new LinkedHashSet<String>();
+                                               sub.put(l1, m);
+                                       }
+                                       m.add(e.subsection);
+                               }
+                               cfg = cfg.baseState;
+                       }
+
+                       sections = new CaseFoldingSet(sec);
+                       subsections = sub;
+               }
+       }
+
+       private static class CaseFoldingSet extends AbstractSet<String> {
+               private final Map<String, String> names;
+
+               CaseFoldingSet(Map<String, String> names) {
+                       this.names = names;
+               }
+
+               @Override
+               public boolean contains(Object needle) {
+                       if (needle instanceof String) {
+                               String n = (String) needle;
+                               return names.containsKey(n)
+                                               || names.containsKey(StringUtils.toLowerCase(n));
+                       }
+                       return false;
+               }
+
+               @Override
+               public Iterator<String> iterator() {
+                       final Iterator<String> i = names.values().iterator();
+                       return new Iterator<String>() {
+                               public boolean hasNext() {
+                                       return i.hasNext();
+                               }
+
+                               public String next() {
+                                       return i.next();
+                               }
+
+                               public void remove() {
+                                       throw new UnsupportedOperationException();
+                               }
+                       };
+               }
+
+               @Override
+               public int size() {
+                       return names.size();
+               }
+       }
 }