Index: lucene/src/java/org/apache/lucene/util/NumericUtils.java =================================================================== --- lucene/src/java/org/apache/lucene/util/NumericUtils.java (revision 964951) +++ lucene/src/java/org/apache/lucene/util/NumericUtils.java (working copy) @@ -446,8 +446,11 @@ final long nextMinBound = (hasLower ? (minBound + diff) : minBound) & ~mask, nextMaxBound = (hasUpper ? (maxBound - diff) : maxBound) & ~mask; - - if (shift+precisionStep>=valSize || nextMinBound>nextMaxBound) { + final boolean + lowerWrapped = nextMinBound < minBound, + upperWrapped = nextMaxBound > maxBound; + + if (shift+precisionStep>=valSize || nextMinBound>nextMaxBound || lowerWrapped || upperWrapped) { // We are in the lowest precision or the next precision is not available. addRange(builder, valSize, minBound, maxBound, shift); // exit the split recursion loop Index: lucene/src/test/org/apache/lucene/util/TestNumericUtils.java =================================================================== --- lucene/src/test/org/apache/lucene/util/TestNumericUtils.java (revision 964951) +++ lucene/src/test/org/apache/lucene/util/TestNumericUtils.java (working copy) @@ -179,6 +179,29 @@ // INFO: Tests for trieCodeLong()/trieCodeInt() not needed because implicitely tested by range filter tests + public void testLongExtremeValues() throws Exception { + // use MAX_VALUE - 1 here, else the for-loop below overflows + assertRangeComplete(Long.MAX_VALUE - 1L, Long.MAX_VALUE - 1L, 4); + } + + private void assertRangeComplete(final long lower, final long upper, int precisionStep) { + final OpenBitSet bits=new OpenBitSet(upper-lower+1); + + NumericUtils.splitLongRange(new NumericUtils.LongRangeBuilder() { + @Override + public void addRange(long min, long max, int shift) { + assertTrue("min, max should be inside bounds", min>=lower && min<=upper && max>=lower && max<=upper); + for (long l=min; l<=max; l++) { + assertFalse("ranges should not overlap", bits.getAndSet(l-lower) ); + } + } + }, precisionStep, lower, upper); + + // after flipping all bits in the range, the cardinality should be zero + bits.flip(0,upper-lower+1); + assertTrue("The sub-range concenated should match the whole range", bits.isEmpty()); + } + /** Note: The neededBounds iterator must be unsigned (easier understanding what's happening) */ protected void assertLongRangeSplit(final long lower, final long upper, int precisionStep, final boolean useBitSet, final Iterator neededBounds