LUCENE-4074: FST Sorter BufferSize causes int overflow if BufferSize > 2048MB

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1341995 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Simon Willnauer 2012-05-23 19:38:26 +00:00
parent 8a0f7f9af6
commit 1d6b468822
2 changed files with 47 additions and 12 deletions

View File

@ -1,6 +1,6 @@
package org.apache.lucene.search.suggest.fst;
/**
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
@ -37,18 +37,18 @@ import org.apache.lucene.util.PriorityQueue;
* @lucene.internal
*/
public final class Sort {
public final static int MB = 1024 * 1024;
public final static int GB = MB * 1024;
public final static long MB = 1024 * 1024;
public final static long GB = MB * 1024;
/**
* Minimum recommended buffer size for sorting.
*/
public final static int MIN_BUFFER_SIZE_MB = 32;
public final static long MIN_BUFFER_SIZE_MB = 32;
/**
* Absolute minimum required buffer size for sorting.
*/
public static final int ABSOLUTE_MIN_SORT_BUFFER_SIZE = MB / 2;
public static final long ABSOLUTE_MIN_SORT_BUFFER_SIZE = MB / 2;
private static final String MIN_BUFFER_SIZE_MSG = "At least 0.5MB RAM buffer is needed";
/**
@ -60,7 +60,7 @@ public final class Sort {
* A bit more descriptive unit for constructors.
*
* @see #automatic()
* @see #megabytes(int)
* @see #megabytes(long)
*/
public static final class BufferSize {
final int bytes;
@ -70,11 +70,19 @@ public final class Sort {
throw new IllegalArgumentException("Buffer too large for Java ("
+ (Integer.MAX_VALUE / MB) + "mb max): " + bytes);
}
if (bytes < ABSOLUTE_MIN_SORT_BUFFER_SIZE) {
throw new IllegalArgumentException(MIN_BUFFER_SIZE_MSG + ": " + bytes);
}
this.bytes = (int) bytes;
}
public static BufferSize megabytes(int mb) {
/**
* Creates a {@link BufferSize} in MB. The given
* values must be $gt; 0 and &lt; 2048.
*/
public static BufferSize megabytes(long mb) {
return new BufferSize(mb * MB);
}
@ -105,7 +113,7 @@ public final class Sort {
sortBufferByteSize = Math.max(ABSOLUTE_MIN_SORT_BUFFER_SIZE, sortBufferByteSize);
}
}
return new BufferSize(Math.min(Integer.MAX_VALUE, sortBufferByteSize));
return new BufferSize(Math.min((long)Integer.MAX_VALUE, sortBufferByteSize));
}
}

View File

@ -63,7 +63,7 @@ public class TestSort extends LuceneTestCase {
public void testIntermediateMerges() throws Exception {
// Sort 20 mb worth of data with 1mb buffer, binary merging.
SortInfo info = checkSort(new Sort(Sort.DEFAULT_COMPARATOR, BufferSize.megabytes(1), Sort.defaultTempDir(), 2),
generateRandom(Sort.MB * 20));
generateRandom((int)Sort.MB * 20));
assertTrue(info.mergeRounds > 10);
}
@ -71,7 +71,7 @@ public class TestSort extends LuceneTestCase {
public void testSmallRandom() throws Exception {
// Sort 20 mb worth of data with 1mb buffer.
SortInfo sortInfo = checkSort(new Sort(Sort.DEFAULT_COMPARATOR, BufferSize.megabytes(1), Sort.defaultTempDir(), Sort.MAX_TEMPFILES),
generateRandom(Sort.MB * 20));
generateRandom((int)Sort.MB * 20));
assertEquals(1, sortInfo.mergeRounds);
}
@ -79,7 +79,7 @@ public class TestSort extends LuceneTestCase {
public void testLargerRandom() throws Exception {
// Sort 100MB worth of data with 15mb buffer.
checkSort(new Sort(Sort.DEFAULT_COMPARATOR, BufferSize.megabytes(16), Sort.defaultTempDir(), Sort.MAX_TEMPFILES),
generateRandom(Sort.MB * 100));
generateRandom((int)Sort.MB * 100));
}
private byte[][] generateRandom(int howMuchData) {
@ -152,4 +152,31 @@ public class TestSort extends LuceneTestCase {
w.close();
return file;
}
public void testRamBuffer() {
int numIters = atLeast(10000);
for (int i = 0; i < numIters; i++) {
BufferSize.megabytes(1+random().nextInt(2047));
}
BufferSize.megabytes(2047);
BufferSize.megabytes(1);
try {
BufferSize.megabytes(2048);
fail("max mb is 2047");
} catch (IllegalArgumentException e) {
}
try {
BufferSize.megabytes(0);
fail("min mb is 0.5");
} catch (IllegalArgumentException e) {
}
try {
BufferSize.megabytes(-1);
fail("min mb is 0.5");
} catch (IllegalArgumentException e) {
}
}
}