mirror of https://github.com/apache/lucene.git
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:
parent
e6a9d9b318
commit
4081e733b1
|
@ -173,7 +173,7 @@ public class RAMDirectory extends Directory implements Serializable {
|
||||||
/** Removes an existing file in the directory.
|
/** Removes an existing file in the directory.
|
||||||
* @throws IOException if the file does not exist
|
* @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);
|
RAMFile file = (RAMFile)fileMap.get(name);
|
||||||
if (file!=null) {
|
if (file!=null) {
|
||||||
fileMap.remove(name);
|
fileMap.remove(name);
|
||||||
|
@ -215,7 +215,7 @@ public class RAMDirectory extends Directory implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a stream reading an existing file. */
|
/** Returns a stream reading an existing file. */
|
||||||
public final IndexInput openInput(String name) throws IOException {
|
public IndexInput openInput(String name) throws IOException {
|
||||||
RAMFile file;
|
RAMFile file;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
file = (RAMFile)fileMap.get(name);
|
file = (RAMFile)fileMap.get(name);
|
||||||
|
|
|
@ -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{
|
public void testDeleteReaderWriterConflictUnoptimized() throws IOException{
|
||||||
deleteReaderWriterConflict(false);
|
deleteReaderWriterConflict(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,11 @@ package org.apache.lucene.store;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a subclass of RAMDirectory that adds methods
|
* This is a subclass of RAMDirectory that adds methods
|
||||||
|
@ -35,18 +38,37 @@ public class MockRAMDirectory extends RAMDirectory {
|
||||||
long maxUsedSize;
|
long maxUsedSize;
|
||||||
double randomIOExceptionRate;
|
double randomIOExceptionRate;
|
||||||
Random randomState;
|
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 {
|
public MockRAMDirectory() throws IOException {
|
||||||
super();
|
super();
|
||||||
|
if (openFiles == null) {
|
||||||
|
openFiles = new HashMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public MockRAMDirectory(String dir) throws IOException {
|
public MockRAMDirectory(String dir) throws IOException {
|
||||||
super(dir);
|
super(dir);
|
||||||
|
if (openFiles == null) {
|
||||||
|
openFiles = new HashMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public MockRAMDirectory(Directory dir) throws IOException {
|
public MockRAMDirectory(Directory dir) throws IOException {
|
||||||
super(dir);
|
super(dir);
|
||||||
|
if (openFiles == null) {
|
||||||
|
openFiles = new HashMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public MockRAMDirectory(File dir) throws IOException {
|
public MockRAMDirectory(File dir) throws IOException {
|
||||||
super(dir);
|
super(dir);
|
||||||
|
if (openFiles == null) {
|
||||||
|
openFiles = new HashMap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMaxSizeInBytes(long maxSize) {
|
public void setMaxSizeInBytes(long maxSize) {
|
||||||
|
@ -67,6 +89,17 @@ public class MockRAMDirectory extends RAMDirectory {
|
||||||
this.maxUsedSize = getRecomputedActualSizeInBytes();
|
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
|
* If 0.0, no exceptions will be thrown. Else this should
|
||||||
* be a double 0.0 - 1.0. We will randomly throw an
|
* 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) {
|
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);
|
RAMFile file = new RAMFile(this);
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
RAMFile existing = (RAMFile)fileMap.get(name);
|
RAMFile existing = (RAMFile)fileMap.get(name);
|
||||||
|
@ -105,6 +157,27 @@ public class MockRAMDirectory extends RAMDirectory {
|
||||||
return new MockRAMOutputStream(this, file);
|
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. */
|
/** Provided for testing purposes. Use sizeInBytes() instead. */
|
||||||
public synchronized final long getRecomputedSizeInBytes() {
|
public synchronized final long getRecomputedSizeInBytes() {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue