From d15303d9d6f0235fad9023c14f5596b495b18986 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:17:13 +0000 Subject: [PATCH 1/7] make branch to debug test fails w/ slow closer git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393532 13f79535-47bb-0310-9956-ffa450edef68 From bbbe0a62ef164d95b477c2529446767b469f9582 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:18:00 +0000 Subject: [PATCH 2/7] add slowcloser git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393533 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/index/StandardDirectoryReader.java | 15 ++++-- .../apache/lucene/index/TestIndexWriter.java | 1 - .../lucene/store/MockDirectoryWrapper.java | 9 +++- .../SlowClosingMockIndexInputWrapper.java | 47 +++++++++++++++++++ 4 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 lucene/test-framework/src/java/org/apache/lucene/store/SlowClosingMockIndexInputWrapper.java diff --git a/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java b/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java index 4bc42b3a462..3f144a8cbba 100644 --- a/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java +++ b/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java @@ -151,7 +151,7 @@ final class StandardDirectoryReader extends DirectoryReader { } boolean success = false; - IOException prior = null; + Throwable prior = null; try { SegmentReader newReader; if (newReaders[i] == null || infos.info(i).info.getUseCompoundFile() != newReaders[i].getSegmentInfo().info.getUseCompoundFile()) { @@ -176,7 +176,7 @@ final class StandardDirectoryReader extends DirectoryReader { } } success = true; - } catch (IOException ex) { + } catch (Throwable ex) { prior = ex; } finally { if (!success) { @@ -192,14 +192,19 @@ final class StandardDirectoryReader extends DirectoryReader { // closing we must decRef it newReaders[i].decRef(); } - } catch (IOException ex) { - if (prior == null) prior = ex; + } catch (Throwable t) { + if (prior == null) prior = t; } } } } // throw the first exception - if (prior != null) throw prior; + if (prior != null) { + if (prior instanceof IOException) throw (IOException) prior; + if (prior instanceof RuntimeException) throw (RuntimeException) prior; + if (prior instanceof Error) throw (Error) prior; + throw new RuntimeException(prior); + } } } return new StandardDirectoryReader(directory, newReaders, writer, infos, termInfosIndexDivisor, false); diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java index a7402fee9bf..3dc5d253c2b 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java @@ -1025,7 +1025,6 @@ public class TestIndexWriter extends LuceneTestCase { } w.close(); w = null; - _TestUtil.checkIndex(dir); DirectoryReader.open(dir).close(); // Strangely, if we interrupt a thread before diff --git a/lucene/test-framework/src/java/org/apache/lucene/store/MockDirectoryWrapper.java b/lucene/test-framework/src/java/org/apache/lucene/store/MockDirectoryWrapper.java index e124423a29b..fcb66de5e32 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/store/MockDirectoryWrapper.java +++ b/lucene/test-framework/src/java/org/apache/lucene/store/MockDirectoryWrapper.java @@ -498,7 +498,14 @@ public class MockDirectoryWrapper extends BaseDirectoryWrapper { throw fillOpenTrace(new IOException("MockDirectoryWrapper: file \"" + name + "\" is still open for writing"), name, false); } - IndexInput ii = new MockIndexInputWrapper(this, name, delegate.openInput(name, LuceneTestCase.newIOContext(randomState, context))); + IndexInput delegateInput = delegate.openInput(name, LuceneTestCase.newIOContext(randomState, context)); + + final IndexInput ii; + if (randomState.nextInt(500) == 0) { + ii = new SlowClosingMockIndexInputWrapper(this, name, delegateInput); + } else { + ii = new MockIndexInputWrapper(this, name, delegateInput); + } addFileHandle(ii, name, Handle.Input); return ii; } diff --git a/lucene/test-framework/src/java/org/apache/lucene/store/SlowClosingMockIndexInputWrapper.java b/lucene/test-framework/src/java/org/apache/lucene/store/SlowClosingMockIndexInputWrapper.java new file mode 100644 index 00000000000..bc2e1da8571 --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/store/SlowClosingMockIndexInputWrapper.java @@ -0,0 +1,47 @@ +package org.apache.lucene.store; + +/* + * 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. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.io.IOException; + +import org.apache.lucene.util.ThreadInterruptedException; + +/** + * hangs onto files a little bit longer (50ms in close). + * MockDirectoryWrapper acts like windows: you can't delete files + * open elsewhere. so the idea is to make race conditions for tiny + * files (like segments) easier to reproduce. + */ +class SlowClosingMockIndexInputWrapper extends MockIndexInputWrapper { + + public SlowClosingMockIndexInputWrapper(MockDirectoryWrapper dir, + String name, IndexInput delegate) { + super(dir, name, delegate); + } + + @Override + public void close() throws IOException { + try { + Thread.sleep(50); + } catch (InterruptedException ie) { + throw new ThreadInterruptedException(ie); + } finally { + super.close(); + } + } +} From a97703f1dfcb4d684fa8bf76e17381ad2da7404a Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:22:53 +0000 Subject: [PATCH 3/7] handle Throwable not just IOE when closing git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393535 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/index/StandardDirectoryReader.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java b/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java index 3f144a8cbba..a9761312d03 100644 --- a/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java +++ b/lucene/core/src/java/org/apache/lucene/index/StandardDirectoryReader.java @@ -334,13 +334,13 @@ final class StandardDirectoryReader extends DirectoryReader { @Override protected void doClose() throws IOException { - IOException ioe = null; + Throwable firstExc = null; for (final AtomicReader r : getSequentialSubReaders()) { // try to close each reader, even if an exception is thrown try { r.decRef(); - } catch (IOException e) { - if (ioe == null) ioe = e; + } catch (Throwable t) { + if (t == null) firstExc = t; } } @@ -351,7 +351,12 @@ final class StandardDirectoryReader extends DirectoryReader { } // throw the first exception - if (ioe != null) throw ioe; + if (firstExc != null) { + if (firstExc instanceof IOException) throw (IOException) firstExc; + if (firstExc instanceof RuntimeException) throw (RuntimeException) firstExc; + if (firstExc instanceof Error) throw (Error) firstExc; + throw new RuntimeException(firstExc); + } } @Override From c4a735490e2c23a003c53afb56959eca737295e7 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:32:01 +0000 Subject: [PATCH 4/7] fix not-closing-on-exc bugs in BlockTreeTermsReader git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393550 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/lucene/codecs/BlockTreeTermsReader.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java b/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java index ecfdaec1997..96c8c28b67c 100644 --- a/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java +++ b/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java @@ -172,12 +172,14 @@ public class BlockTreeTermsReader extends FieldsProducer { throw new CorruptIndexException("duplicate field: " + fieldInfo.name + " (resource=" + in + ")"); } } + if (indexDivisor != -1) { + indexIn.close(); + } + success = true; } finally { if (!success) { - IOUtils.closeWhileHandlingException(indexIn, this); - } else if (indexDivisor != -1) { - indexIn.close(); + IOUtils.closeWhileHandlingException(in, indexIn, this); } } } From 4485a42a03f9778e86a433468a977c153e95e98e Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:35:52 +0000 Subject: [PATCH 5/7] fix not-closing-on-exc bugs in BloomFilteringPF git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393552 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/codecs/bloom/BloomFilteringPostingsFormat.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java index 4836391b80f..4ea37905160 100644 --- a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java +++ b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java @@ -159,6 +159,7 @@ public final class BloomFilteringPostingsFormat extends PostingsFormat { String bloomFileName = IndexFileNames.segmentFileName( state.segmentInfo.name, state.segmentSuffix, BLOOM_EXTENSION); IndexInput bloomIn = null; + boolean success = false; try { bloomIn = state.dir.openInput(bloomFileName, state.context); CodecUtil.checkHeader(bloomIn, BLOOM_CODEC_NAME, BLOOM_CODEC_VERSION, @@ -178,8 +179,13 @@ public final class BloomFilteringPostingsFormat extends PostingsFormat { FieldInfo fieldInfo = state.fieldInfos.fieldInfo(fieldNum); bloomsByFieldName.put(fieldInfo.name, bloom); } + success = true; } finally { - IOUtils.close(bloomIn); + if (!success) { + IOUtils.close(bloomIn, delegateFieldsProducer); + } else { + IOUtils.close(bloomIn); + } } } From c34e9434c4481c0459a354b1ee68ab25e585412e Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:49:40 +0000 Subject: [PATCH 6/7] more close-on-exc bugs git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393565 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/codecs/bloom/BloomFilteringPostingsFormat.java | 4 +--- .../java/org/apache/lucene/codecs/BlockTreeTermsReader.java | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java index 4ea37905160..47802bc7224 100644 --- a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java +++ b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java @@ -179,15 +179,13 @@ public final class BloomFilteringPostingsFormat extends PostingsFormat { FieldInfo fieldInfo = state.fieldInfos.fieldInfo(fieldNum); bloomsByFieldName.put(fieldInfo.name, bloom); } + IOUtils.close(bloomIn); success = true; } finally { if (!success) { IOUtils.close(bloomIn, delegateFieldsProducer); - } else { - IOUtils.close(bloomIn); } } - } public Iterator iterator() { diff --git a/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java b/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java index 96c8c28b67c..72c9a743009 100644 --- a/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java +++ b/lucene/core/src/java/org/apache/lucene/codecs/BlockTreeTermsReader.java @@ -179,7 +179,8 @@ public class BlockTreeTermsReader extends FieldsProducer { success = true; } finally { if (!success) { - IOUtils.closeWhileHandlingException(in, indexIn, this); + // this.close() will close in: + IOUtils.closeWhileHandlingException(indexIn, this); } } } From 38f1194d4724cf6a582d1c40180457fc8ac23131 Mon Sep 17 00:00:00 2001 From: Michael McCandless Date: Wed, 3 Oct 2012 15:51:56 +0000 Subject: [PATCH 7/7] use closeWhileHandlingException when success is false git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/slowclosing@1393566 13f79535-47bb-0310-9956-ffa450edef68 --- .../lucene/codecs/bloom/BloomFilteringPostingsFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java index 47802bc7224..ff4472b222e 100644 --- a/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java +++ b/lucene/codecs/src/java/org/apache/lucene/codecs/bloom/BloomFilteringPostingsFormat.java @@ -183,7 +183,7 @@ public final class BloomFilteringPostingsFormat extends PostingsFormat { success = true; } finally { if (!success) { - IOUtils.close(bloomIn, delegateFieldsProducer); + IOUtils.closeWhileHandlingException(bloomIn, delegateFieldsProducer); } } }