Index config section and subsection names in one pass
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
This commit is contained in:
parent
2ba67bedae
commit
c0b1443926
|
@ -414,9 +414,9 @@ public void test009_readNamesInSection() throws ConfigInvalidException {
|
|||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -52,14 +52,9 @@
|
|||
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 String[] getStringList(final String section, String subsection,
|
|||
* 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 Set<String> getNames(String section) {
|
|||
* @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 static interface SectionParser<T> {
|
|||
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;
|
||||
|
||||
|
|
|
@ -52,19 +52,29 @@
|
|||
|
||||
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 @@ public int compare(ConfigLine a, ConfigLine b) {
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue