Index: src/java/org/apache/lucene/index/LogMergePolicy.java =================================================================== --- src/java/org/apache/lucene/index/LogMergePolicy.java (revision 600921) +++ src/java/org/apache/lucene/index/LogMergePolicy.java (working copy) @@ -19,6 +19,8 @@ import java.io.IOException; import java.util.Set; +import java.util.Arrays; +import java.util.Comparator; import org.apache.lucene.store.Directory; @@ -59,6 +61,7 @@ long maxMergeSize; int maxMergeDocs = DEFAULT_MAX_MERGE_DOCS; + private boolean requireContiguousMerge = false; private boolean useCompoundFile = true; private boolean useCompoundDocStore = true; private IndexWriter writer; @@ -68,6 +71,16 @@ writer.message("LMP: " + message); } + // nocommit javadoc + public void setRequireContiguousMerge(boolean v) { + requireContiguousMerge = v; + } + + // nocommit javadoc + public boolean getRequireContiguousMerge() { + return requireContiguousMerge; + } + /**

Returns the number of segments that are merged at * once and also controls the total number of segments * allowed to accumulate in the index.

*/ @@ -159,6 +172,7 @@ info.getUseCompoundFile() == useCompoundFile; } + // nocommit -- must make this work for non-contiguosu case too /** Returns the merges necessary to optimize the index. * This merge policy defines "optimized" to mean only one * segment in the index, where that segment has no @@ -245,6 +259,37 @@ return spec; } + private static class SegmentInfoAndLevel implements Comparable { + SegmentInfo info; + float level; + int index; + + public SegmentInfoAndLevel(SegmentInfo info, float level, int index) { + this.info = info; + this.level = level; + this.index = index; + } + + // Sorts largest to smallest + public int compareTo(Object o) { + SegmentInfoAndLevel other = (SegmentInfoAndLevel) o; + if (level < other.level) + return 1; + else if (level > other.level) + return -1; + else + return 0; + } + } + + private static class SortByIndex implements Comparator { + public int compare(Object o1, Object o2) { + final SegmentInfoAndLevel sl1 = (SegmentInfoAndLevel) o1; + final SegmentInfoAndLevel sl2 = (SegmentInfoAndLevel) o2; + return sl1.index - sl2.index; + } + } + /** Checks if any merges are now necessary and returns a * {@link MergePolicy.MergeSpecification} if so. A merge * is necessary when there are more than {@link @@ -260,7 +305,7 @@ // Compute levels, which is just log (base mergeFactor) // of the size of each segment - float[] levels = new float[numSegments]; + SegmentInfoAndLevel[] levels = new SegmentInfoAndLevel[numSegments]; final float norm = (float) Math.log(mergeFactor); final Directory directory = writer.getDirectory(); @@ -279,9 +324,12 @@ // Floor tiny segments if (size < 1) size = 1; - levels[i] = (float) Math.log(size)/norm; + levels[i] = new SegmentInfoAndLevel(info, (float) Math.log(size)/norm, i); } + if (!requireContiguousMerge) + Arrays.sort(levels); + final float levelFloor; if (minMergeSize <= 0) levelFloor = (float) 0.0; @@ -302,9 +350,9 @@ // Find max level of all segments not already // quantized. - float maxLevel = levels[start]; + float maxLevel = levels[start].level; for(int i=1+start;i maxLevel) maxLevel = level; } @@ -325,7 +373,7 @@ int upto = numSegments-1; while(upto >= start) { - if (levels[upto] >= levelBottom) { + if (levels[upto].level >= levelBottom) { break; } upto--; @@ -337,7 +385,7 @@ while(end <= 1+upto) { boolean anyTooLarge = false; for(int i=start;i= maxMergeSize || info.docCount >= maxMergeDocs); } @@ -345,7 +393,15 @@ if (spec == null) spec = new MergeSpecification(); message(" " + start + " to " + end + ": add this merge"); - spec.add(new OneMerge(infos.range(start, end), useCompoundFile)); + + Arrays.sort(levels, start, end, new SortByIndex()); + + final SegmentInfos mergeInfos = new SegmentInfos(); + for(int i=start;i= numSegments || !segmentInfos.info(first+i).equals(info)) { - if (segmentInfos.indexOf(info) == -1) - throw new MergePolicy.MergeException("MergePolicy selected a segment (" + info.name + ") that is not in the index"); - else - throw new MergePolicy.MergeException("MergePolicy selected non-contiguous segments to merge (" + merge + " vs " + segString() + "), which IndexWriter (currently) cannot handle"); - } + if (segmentInfos.indexOf(info) == -1) + throw new MergePolicy.MergeException("MergePolicy selected a segment (" + info.name + ") that is not in the index: " + segString()); } - - return first; } - /* FIXME if we want to support non-contiguous segment merges */ synchronized private boolean commitMerge(MergePolicy.OneMerge merge) throws IOException { assert merge.registerDone; @@ -2616,13 +2601,13 @@ boolean success = false; - int start; + SegmentInfos sourceSegments = merge.segments; + final int numSegmentsToMerge = sourceSegments.size(); try { SegmentInfos sourceSegmentsClone = merge.segmentsClone; - SegmentInfos sourceSegments = merge.segments; - start = ensureContiguousMerge(merge); + ensureValidMerge(merge); if (infoStream != null) message("commitMerge " + merge.segString(directory)); @@ -2632,7 +2617,6 @@ BitVector deletes = null; int docUpto = 0; - final int numSegmentsToMerge = sourceSegments.size(); for(int i=0;i