1 package org.apache.lucene.store;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 import java.io.IOException;
22 import java.io.RandomAccessFile;
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 {
32 /** Create a new SimpleFSDirectory for the named location.
34 * @param path the path of the directory
35 * @param lockFactory the lock factory to use, or null for the default
36 * ({@link NativeFSLockFactory});
39 public SimpleFSDirectory(File path, LockFactory lockFactory) throws IOException {
40 super(path, lockFactory);
43 /** Create a new SimpleFSDirectory for the named location and {@link NativeFSLockFactory}.
45 * @param path the path of the directory
48 public SimpleFSDirectory(File path) throws IOException {
52 /** Creates an IndexInput for the file with the given name. */
54 public IndexInput openInput(String name, int bufferSize) throws IOException {
56 return new SimpleFSIndexInput(new File(directory, name), bufferSize, getReadChunkSize());
59 protected static class SimpleFSIndexInput extends BufferedIndexInput {
61 protected static class Descriptor extends RandomAccessFile {
62 // remember if the file is open, so that we don't try to close it
64 protected volatile boolean isOpen;
68 public Descriptor(File file, String mode) throws IOException {
75 public void close() throws IOException {
83 protected final Descriptor file;
85 // LUCENE-1566 - maximum read length on a 32bit JVM to prevent incorrect OOM
86 protected final int chunkSize;
88 public SimpleFSIndexInput(File path, int bufferSize, int chunkSize) throws IOException {
90 file = new Descriptor(path, "r");
91 this.chunkSize = chunkSize;
94 /** IndexInput methods */
96 protected void readInternal(byte[] b, int offset, int len)
99 long position = getFilePointer();
100 if (position != file.position) {
102 file.position = position;
108 final int readLength;
109 if (total + chunkSize > len) {
110 readLength = len - total;
112 // LUCENE-1566 - work around JVM Bug by breaking very large reads into chunks
113 readLength = chunkSize;
115 final int i = file.read(b, offset + total, readLength);
117 throw new IOException("read past EOF");
121 } while (total < len);
122 } catch (OutOfMemoryError e) {
123 // propagate OOM up and add a hint for 32bit VM Users hitting the bug
124 // with a large chunk size in the fast path.
125 final OutOfMemoryError outOfMemoryError = new OutOfMemoryError(
126 "OutOfMemoryError likely caused by the Sun VM Bug described in "
127 + "https://issues.apache.org/jira/browse/LUCENE-1566; try calling FSDirectory.setReadChunkSize "
128 + "with a value smaller than the current chunk size (" + chunkSize + ")");
129 outOfMemoryError.initCause(e);
130 throw outOfMemoryError;
136 public void close() throws IOException {
137 // only close the file if this is not a clone
138 if (!isClone) file.close();
142 protected void seekInternal(long position) {
146 public long length() {
151 public Object clone() {
152 SimpleFSIndexInput clone = (SimpleFSIndexInput)super.clone();
153 clone.isClone = true;
157 /** Method used for testing. Returns true if the underlying
158 * file descriptor is valid.
160 boolean isFDValid() throws IOException {
161 return file.getFD().valid();
165 public void copyBytes(IndexOutput out, long numBytes) throws IOException {
166 numBytes -= flushBuffer(out, numBytes);
167 // If out is FSIndexOutput, the copy will be optimized
168 out.copyBytes(this, numBytes);