pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / store / SimpleFSDirectory.java
1 package org.apache.lucene.store;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.RandomAccessFile;
23
24 /** A straightforward implementation of {@link FSDirectory}
25  *  using java.io.RandomAccessFile.  However, this class has
26  *  poor concurrent performance (multiple threads will
27  *  bottleneck) as it synchronizes when multiple threads
28  *  read from the same file.  It's usually better to use
29  *  {@link NIOFSDirectory} or {@link MMapDirectory} instead. */
30 public class SimpleFSDirectory extends FSDirectory {
31     
32   /** Create a new SimpleFSDirectory for the named location.
33    *
34    * @param path the path of the directory
35    * @param lockFactory the lock factory to use, or null for the default
36    * ({@link NativeFSLockFactory});
37    * @throws IOException
38    */
39   public SimpleFSDirectory(File path, LockFactory lockFactory) throws IOException {
40     super(path, lockFactory);
41   }
42   
43   /** Create a new SimpleFSDirectory for the named location and {@link NativeFSLockFactory}.
44    *
45    * @param path the path of the directory
46    * @throws IOException
47    */
48   public SimpleFSDirectory(File path) throws IOException {
49     super(path, null);
50   }
51
52   /** Creates an IndexInput for the file with the given name. */
53   @Override
54   public IndexInput openInput(String name, int bufferSize) throws IOException {
55     ensureOpen();
56     final File path = new File(directory, name);
57     return new SimpleFSIndexInput("SimpleFSIndexInput(path=\"" + path.getPath() + "\")", path, bufferSize, getReadChunkSize());
58   }
59
60   protected static class SimpleFSIndexInput extends BufferedIndexInput {
61   
62     protected static class Descriptor extends RandomAccessFile {
63       // remember if the file is open, so that we don't try to close it
64       // more than once
65       protected volatile boolean isOpen;
66       long position;
67       final long length;
68       
69       public Descriptor(File file, String mode) throws IOException {
70         super(file, mode);
71         isOpen=true;
72         length=length();
73       }
74   
75       @Override
76       public void close() throws IOException {
77         if (isOpen) {
78           isOpen=false;
79           super.close();
80         }
81       }
82     }
83   
84     protected final Descriptor file;
85     boolean isClone;
86     //  LUCENE-1566 - maximum read length on a 32bit JVM to prevent incorrect OOM 
87     protected final int chunkSize;
88
89     /** @deprecated please pass resourceDesc */
90     @Deprecated
91     public SimpleFSIndexInput(File path, int bufferSize, int chunkSize) throws IOException {
92       this("anonymous SimpleFSIndexInput", path, bufferSize, chunkSize);
93     }
94
95     public SimpleFSIndexInput(String resourceDesc, File path, int bufferSize, int chunkSize) throws IOException {
96       super(resourceDesc, bufferSize);
97       file = new Descriptor(path, "r");
98       this.chunkSize = chunkSize;
99     }
100   
101     /** IndexInput methods */
102     @Override
103     protected void readInternal(byte[] b, int offset, int len)
104          throws IOException {
105       synchronized (file) {
106         long position = getFilePointer();
107         if (position != file.position) {
108           file.seek(position);
109           file.position = position;
110         }
111         int total = 0;
112
113         try {
114           do {
115             final int readLength;
116             if (total + chunkSize > len) {
117               readLength = len - total;
118             } else {
119               // LUCENE-1566 - work around JVM Bug by breaking very large reads into chunks
120               readLength = chunkSize;
121             }
122             final int i = file.read(b, offset + total, readLength);
123             if (i == -1) {
124               throw new IOException("read past EOF");
125             }
126             file.position += i;
127             total += i;
128           } while (total < len);
129         } catch (OutOfMemoryError e) {
130           // propagate OOM up and add a hint for 32bit VM Users hitting the bug
131           // with a large chunk size in the fast path.
132           final OutOfMemoryError outOfMemoryError = new OutOfMemoryError(
133               "OutOfMemoryError likely caused by the Sun VM Bug described in "
134               + "https://issues.apache.org/jira/browse/LUCENE-1566; try calling FSDirectory.setReadChunkSize "
135               + "with a value smaller than the current chunk size (" + chunkSize + ")");
136           outOfMemoryError.initCause(e);
137           throw outOfMemoryError;
138         } catch (IOException ioe) {
139           IOException newIOE = new IOException(ioe.getMessage() + ": " + this);
140           newIOE.initCause(ioe);
141           throw newIOE;
142         }
143       }
144     }
145   
146     @Override
147     public void close() throws IOException {
148       // only close the file if this is not a clone
149       if (!isClone) file.close();
150     }
151   
152     @Override
153     protected void seekInternal(long position) {
154     }
155   
156     @Override
157     public long length() {
158       return file.length;
159     }
160   
161     @Override
162     public Object clone() {
163       SimpleFSIndexInput clone = (SimpleFSIndexInput)super.clone();
164       clone.isClone = true;
165       return clone;
166     }
167   
168     /** Method used for testing. Returns true if the underlying
169      *  file descriptor is valid.
170      */
171     boolean isFDValid() throws IOException {
172       return file.getFD().valid();
173     }
174     
175     @Override
176     public void copyBytes(IndexOutput out, long numBytes) throws IOException {
177       numBytes -= flushBuffer(out, numBytes);
178       // If out is FSIndexOutput, the copy will be optimized
179       out.copyBytes(this, numBytes);
180     }
181   }
182 }