LUCENE-6745: RAMInputStream.clone was not thread safe (Mike McCandless)

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1696798 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2015-08-20 14:39:30 +00:00
parent fd33cfdc03
commit be9471debb
3 changed files with 73 additions and 2 deletions

View File

@ -79,6 +79,8 @@ Bug Fixes
test data. In addition, the performance of those filters was improved
significantly. (Uwe Schindler, Robert Muir)
* LUCENE-6745: RAMInputStream.clone was not thread safe (Mike McCandless)
Other
* LUCENE-6174: Improve "ant eclipse" to select right JRE for building.

View File

@ -116,7 +116,7 @@ public class RAMInputStream extends IndexInput implements Cloneable {
@Override
public void seek(long pos) throws IOException {
if (currentBuffer==null || pos < bufferStart || pos >= bufferStart + BUFFER_SIZE) {
if (currentBuffer == null || pos < bufferStart || pos >= bufferStart + BUFFER_SIZE) {
currentBufferIndex = (int) (pos / BUFFER_SIZE);
switchCurrentBuffer(false);
}
@ -157,4 +157,19 @@ public class RAMInputStream extends IndexInput implements Cloneable {
}
};
}
@Override
public RAMInputStream clone() {
RAMInputStream clone = (RAMInputStream) super.clone();
// If another thread was using our instance, this new clone could have a mismatched currentBuffer and currentBufferIndex, so we do
// a "fresh seek" here:
clone.currentBuffer = null;
try {
clone.seek(getFilePointer());
} catch (IOException ioe) {
// Should not happen!
throw new AssertionError(ioe);
}
return clone;
}
}

View File

@ -1167,5 +1167,59 @@ public abstract class BaseDirectoryTestCase extends LuceneTestCase {
in.close(); // close again
dir.close();
}
}
public void testCloneThreadSafety() throws Exception {
Directory dir = getDirectory(createTempDir());
IndexOutput out = dir.createOutput("randombytes", IOContext.DEFAULT);
// Write file with at least 20 K random bytes:
final int numBytes = atLeast(20*1024);
final byte[] bytes = new byte[numBytes];
random().nextBytes(bytes);
out.writeBytes(bytes, 0, bytes.length);
out.close();
// Then read the bytes back at random seek points from multiple threads:
final IndexInput in = dir.openInput("randombytes", IOContext.DEFAULT);
int numThreads = 4;
Thread[] threads = new Thread[numThreads];
for(int i=0;i<numThreads;i++) {
int finalI = i;
threads[i] = new Thread() {
@Override
public void run() {
int numIters = atLeast(1000);
byte[] scratch = new byte[numBytes];
for(int iter=0;iter<numIters;iter++) {
// First thread uses the original IndexInput, all other threads use clone:
IndexInput myIn;
if (finalI == 0) {
myIn = in;
} else {
myIn = in.clone();
}
int spot = random().nextInt(numBytes/2);
try {
myIn.seek(spot);
int length = numBytes-spot;
myIn.readBytes(scratch, 0, length);
for(int i=0;i<length;i++) {
assertEquals(bytes[spot+i], scratch[i]);
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
};
threads[i].start();
}
for(Thread thread : threads) {
thread.join();
}
in.close();
dir.close();
}
}