LUCENE-6325: use array for number -> FieldInfo lookup, except in very sparse cases

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1687789 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2015-06-26 15:54:03 +00:00
parent 75c60be660
commit 42fdbbeb95
2 changed files with 36 additions and 4 deletions

View File

@ -225,6 +225,10 @@ Optimizations
with a filter of "baz" will internally leapfrog foo,bar,baz as one
conjunction. (Ryan Ernst, Robert Muir, Adrien Grande)
* LUCENE-6325: Reduce RAM usage of FieldInfos, and speed up lookup by
number, by using an array instead of TreeMap except in very sparse
cases (Robert Muir, Mike McCandless)
Build
* LUCENE-6518: Don't report false thread leaks from IBM J9

View File

@ -25,6 +25,8 @@ import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.apache.lucene.util.ArrayUtil;
/**
* Collection of {@link FieldInfo}s (accessible by number or by name).
* @lucene.experimental
@ -38,7 +40,10 @@ public class FieldInfos implements Iterable<FieldInfo> {
private final boolean hasNorms;
private final boolean hasDocValues;
private final SortedMap<Integer,FieldInfo> byNumber = new TreeMap<>();
// used only by fieldInfo(int)
private final FieldInfo[] byNumberTable; // contiguous
private final SortedMap<Integer,FieldInfo> byNumberMap; // sparse
private final HashMap<String,FieldInfo> byName = new HashMap<>();
private final Collection<FieldInfo> values; // for an unmodifiable iterator
@ -54,6 +59,7 @@ public class FieldInfos implements Iterable<FieldInfo> {
boolean hasNorms = false;
boolean hasDocValues = false;
TreeMap<Integer, FieldInfo> byNumber = new TreeMap<>();
for (FieldInfo info : infos) {
if (info.number < 0) {
throw new IllegalArgumentException("illegal field number: " + info.number + " for field " + info.name);
@ -84,6 +90,22 @@ public class FieldInfos implements Iterable<FieldInfo> {
this.hasNorms = hasNorms;
this.hasDocValues = hasDocValues;
this.values = Collections.unmodifiableCollection(byNumber.values());
Integer max = byNumber.isEmpty() ? null : Collections.max(byNumber.keySet());
// Only usee TreeMap in the very sparse case (< 1/16th of the numbers are used),
// because TreeMap uses ~ 64 (32 bit JVM) or 120 (64 bit JVM w/o compressed oops)
// overall bytes per entry, but array uses 4 (32 bit JMV) or 8
// (64 bit JVM w/o compressed oops):
if (max != null && max < ArrayUtil.MAX_ARRAY_LENGTH && max < 16L*byNumber.size()) {
byNumberMap = null;
byNumberTable = new FieldInfo[max+1];
for (Map.Entry<Integer,FieldInfo> entry : byNumber.entrySet()) {
byNumberTable[entry.getKey()] = entry.getValue();
}
} else {
byNumberMap = byNumber;
byNumberTable = null;
}
}
/** Returns true if any fields have freqs */
@ -123,8 +145,7 @@ public class FieldInfos implements Iterable<FieldInfo> {
/** Returns the number of fields */
public int size() {
assert byNumber.size() == byName.size();
return byNumber.size();
return byName.size();
}
/**
@ -157,7 +178,14 @@ public class FieldInfos implements Iterable<FieldInfo> {
if (fieldNumber < 0) {
throw new IllegalArgumentException("Illegal field number: " + fieldNumber);
}
return byNumber.get(fieldNumber);
if (byNumberTable != null) {
if (fieldNumber >= byNumberTable.length) {
return null;
}
return byNumberTable[fieldNumber];
} else {
return byNumberMap.get(fieldNumber);
}
}
static final class FieldNumbers {