diff --git a/src/java/org/apache/lucene/store/RAMDirectory.java b/src/java/org/apache/lucene/store/RAMDirectory.java index 8c2e0338478..d640ab5088d 100644 --- a/src/java/org/apache/lucene/store/RAMDirectory.java +++ b/src/java/org/apache/lucene/store/RAMDirectory.java @@ -173,7 +173,7 @@ public class RAMDirectory extends Directory implements Serializable { /** Removes an existing file in the directory. * @throws IOException if the file does not exist */ - public synchronized final void deleteFile(String name) throws IOException { + public synchronized void deleteFile(String name) throws IOException { RAMFile file = (RAMFile)fileMap.get(name); if (file!=null) { fileMap.remove(name); @@ -215,7 +215,7 @@ public class RAMDirectory extends Directory implements Serializable { } /** Returns a stream reading an existing file. */ - public final IndexInput openInput(String name) throws IOException { + public IndexInput openInput(String name) throws IOException { RAMFile file; synchronized (this) { file = (RAMFile)fileMap.get(name); diff --git a/src/test/org/apache/lucene/index/TestIndexReader.java b/src/test/org/apache/lucene/index/TestIndexReader.java index 9b673345362..2516df05f2e 100644 --- a/src/test/org/apache/lucene/index/TestIndexReader.java +++ b/src/test/org/apache/lucene/index/TestIndexReader.java @@ -386,6 +386,38 @@ public class TestIndexReader extends TestCase } + // Make sure you can set norms & commit, and there are + // no extra norms files left: + public void testWritingNormsNoReader() throws IOException + { + Directory dir = new MockRAMDirectory(); + IndexWriter writer = null; + IndexReader reader = null; + Term searchTerm = new Term("content", "aaa"); + + // add 1 documents with term : aaa + writer = new IndexWriter(dir, new WhitespaceAnalyzer(), true); + writer.setUseCompoundFile(false); + addDoc(writer, searchTerm.text()); + writer.close(); + + // now open reader & set norm for doc 0 (writes to + // _0_1.s0) + reader = IndexReader.open(dir); + reader.setNorm(0, "content", (float) 2.0); + reader.close(); + + // now open reader again & set norm for doc 0 (writes to _0_2.s0) + reader = IndexReader.open(dir); + reader.setNorm(0, "content", (float) 2.0); + reader.close(); + assertFalse("failed to remove first generation norms file on writing second generation", + dir.fileExists("_0_1.s0")); + + dir.close(); + } + + public void testDeleteReaderWriterConflictUnoptimized() throws IOException{ deleteReaderWriterConflict(false); } diff --git a/src/test/org/apache/lucene/store/MockRAMDirectory.java b/src/test/org/apache/lucene/store/MockRAMDirectory.java index ca1e43f3260..101afd20105 100644 --- a/src/test/org/apache/lucene/store/MockRAMDirectory.java +++ b/src/test/org/apache/lucene/store/MockRAMDirectory.java @@ -19,8 +19,11 @@ package org.apache.lucene.store; import java.io.IOException; import java.io.File; +import java.io.FileNotFoundException; import java.util.Iterator; import java.util.Random; +import java.util.Map; +import java.util.HashMap; /** * This is a subclass of RAMDirectory that adds methods @@ -35,18 +38,37 @@ public class MockRAMDirectory extends RAMDirectory { long maxUsedSize; double randomIOExceptionRate; Random randomState; + boolean noDeleteOpenFile = true; + + // NOTE: we cannot initialize the Map here due to the + // order in which our constructor actually does this + // member initialization vs when it calls super. It seems + // like super is called, then our members are initialized: + Map openFiles; public MockRAMDirectory() throws IOException { super(); + if (openFiles == null) { + openFiles = new HashMap(); + } } public MockRAMDirectory(String dir) throws IOException { super(dir); + if (openFiles == null) { + openFiles = new HashMap(); + } } public MockRAMDirectory(Directory dir) throws IOException { super(dir); + if (openFiles == null) { + openFiles = new HashMap(); + } } public MockRAMDirectory(File dir) throws IOException { super(dir); + if (openFiles == null) { + openFiles = new HashMap(); + } } public void setMaxSizeInBytes(long maxSize) { @@ -67,6 +89,17 @@ public class MockRAMDirectory extends RAMDirectory { this.maxUsedSize = getRecomputedActualSizeInBytes(); } + /** + * Emulate windows whereby deleting an open file is not + * allowed (raise IOException). + */ + public void setNoDeleteOpenFile(boolean value) { + this.noDeleteOpenFile = value; + } + public boolean getNoDeleteOpenFile() { + return noDeleteOpenFile; + } + /** * If 0.0, no exceptions will be thrown. Else this should * be a double 0.0 - 1.0. We will randomly throw an @@ -91,7 +124,26 @@ public class MockRAMDirectory extends RAMDirectory { } } + public synchronized void deleteFile(String name) throws IOException { + synchronized(openFiles) { + if (noDeleteOpenFile && openFiles.containsKey(name)) { + throw new IOException("MockRAMDirectory: file \"" + name + "\" is still open: cannot delete"); + } + } + super.deleteFile(name); + } + public IndexOutput createOutput(String name) { + if (openFiles == null) { + openFiles = new HashMap(); + } + synchronized(openFiles) { + if (noDeleteOpenFile && openFiles.containsKey(name)) { + // RuntimeException instead of IOException because + // super() does not throw IOException currently: + throw new RuntimeException("MockRAMDirectory: file \"" + name + "\" is still open: cannot overwrite"); + } + } RAMFile file = new RAMFile(this); synchronized (this) { RAMFile existing = (RAMFile)fileMap.get(name); @@ -105,6 +157,27 @@ public class MockRAMDirectory extends RAMDirectory { return new MockRAMOutputStream(this, file); } + public IndexInput openInput(String name) throws IOException { + RAMFile file; + synchronized (this) { + file = (RAMFile)fileMap.get(name); + } + if (file == null) + throw new FileNotFoundException(name); + else { + synchronized(openFiles) { + if (openFiles.containsKey(name)) { + Integer v = (Integer) openFiles.get(name); + v = new Integer(v.intValue()+1); + openFiles.put(name, v); + } else { + openFiles.put(name, new Integer(1)); + } + } + } + return new MockRAMInputStream(this, name, file); + } + /** Provided for testing purposes. Use sizeInBytes() instead. */ public synchronized final long getRecomputedSizeInBytes() { long size = 0; diff --git a/src/test/org/apache/lucene/store/MockRAMInputStream.java b/src/test/org/apache/lucene/store/MockRAMInputStream.java new file mode 100644 index 00000000000..4cf67053c34 --- /dev/null +++ b/src/test/org/apache/lucene/store/MockRAMInputStream.java @@ -0,0 +1,62 @@ +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. + */ + +/** + * Used by MockRAMDirectory to create an input stream that + * keeps track of when it's been closed. + */ + +public class MockRAMInputStream extends RAMInputStream { + private MockRAMDirectory dir; + private String name; + + /** Construct an empty output buffer. */ + public MockRAMInputStream(MockRAMDirectory dir, String name, RAMFile f) { + super(f); + this.name = name; + this.dir = dir; + } + + public void close() { + super.close(); + synchronized(dir.openFiles) { + Integer v = (Integer) dir.openFiles.get(name); + if (v.intValue() == 1) { + dir.openFiles.remove(name); + } else { + v = new Integer(v.intValue()-1); + dir.openFiles.put(name, v); + } + } + } + + public Object clone() { + MockRAMInputStream clone = (MockRAMInputStream) super.clone(); + synchronized(dir.openFiles) { + if (dir.openFiles.containsKey(name)) { + Integer v = (Integer) dir.openFiles.get(name); + v = new Integer(v.intValue()+1); + dir.openFiles.put(name, v); + } else { + throw new RuntimeException("BUG: cloned file was not open?"); + } + } + return clone; + } +}