LUCENE-820: improve MockRAMDirectory to mimic Windows (can't delete open files); added test case for this bug (this root cause of this bug was already fixed by the fix to LUCENE-821)

git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@514370 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael McCandless 2007-03-04 08:25:31 +00:00
parent e6a9d9b318
commit 4081e733b1
4 changed files with 169 additions and 2 deletions

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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;
}
}