diff --git a/solr/core/src/java/org/apache/solr/index/LatestVersionFilterMergePolicy.java b/solr/core/src/java/org/apache/solr/index/LatestVersionFilterMergePolicy.java new file mode 100644 index 00000000000..5841f99fb75 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/index/LatestVersionFilterMergePolicy.java @@ -0,0 +1,75 @@ +package org.apache.solr.index; + +import java.io.IOException; +import java.util.Map; +import org.apache.lucene.index.FilterMergePolicy; +import org.apache.lucene.index.MergePolicy; +import org.apache.lucene.index.MergeTrigger; +import org.apache.lucene.index.SegmentCommitInfo; +import org.apache.lucene.index.SegmentInfos; +import org.apache.lucene.util.Version; + +/** + * Prevents any older version segment (< {@link Version.LATEST}), either original or one derived as + * a result of merging with an older version segment, from being considered for merges. That way a + * snapshot of older segments remains consistent. This assists in upgrading to a future Lucene major + * version if existing documents are reindexed in the current version with this merge policy in + * place. + */ +public class LatestVersionFilterMergePolicy extends FilterMergePolicy { + + public LatestVersionFilterMergePolicy(MergePolicy in) { + super(in); + } + + @Override + public MergeSpecification findMerges( + MergeTrigger mergeTrigger, SegmentInfos infos, MergeContext mergeContext) throws IOException { + return in.findMerges(mergeTrigger, getFilteredInfosClone(infos), mergeContext); + } + + @Override + public MergeSpecification findForcedMerges( + SegmentInfos infos, + int maxSegmentCount, + Map segmentsToMerge, + MergeContext mergeContext) + throws IOException { + return in.findForcedMerges( + getFilteredInfosClone(infos), maxSegmentCount, segmentsToMerge, mergeContext); + } + + @Override + public MergeSpecification findForcedDeletesMerges(SegmentInfos infos, MergeContext mergeContext) + throws IOException { + return in.findForcedDeletesMerges(getFilteredInfosClone(infos), mergeContext); + } + + @Override + public MergeSpecification findFullFlushMerges( + MergeTrigger mergeTrigger, SegmentInfos infos, MergeContext mergeContext) throws IOException { + return in.findFullFlushMerges(mergeTrigger, getFilteredInfosClone(infos), mergeContext); + } + + private SegmentInfos getFilteredInfosClone(SegmentInfos infos) { + // We should not remove from the original SegmentInfos. Hence we clone. + SegmentInfos infosClone = infos.clone(); + infosClone.clear(); + for (SegmentCommitInfo info : infos) { + if (allowSegmentForMerge(info)) { + infosClone.add(info); + } + } + return infosClone; + } + + /** + * Determines if a SegmentCommitInfo should be part of the candidate set of segments that will be + * considered for merges. By default, we only allow LATEST version segments to participate in + * merges. + */ + protected boolean allowSegmentForMerge(SegmentCommitInfo info) { + return info.info.getMinVersion() != null + && info.info.getMinVersion().major == Version.LATEST.major; + } +}