001: package org.apache.lucene.store;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.IOException;
021: import java.io.FileNotFoundException;
022: import java.io.File;
023: import java.io.Serializable;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.Set;
027:
028: /**
029: * A memory-resident {@link Directory} implementation. Locking
030: * implementation is by default the {@link SingleInstanceLockFactory}
031: * but can be changed with {@link #setLockFactory}.
032: *
033: * @version $Id: RAMDirectory.java 581625 2007-10-03 15:24:12Z mikemccand $
034: */
035: public class RAMDirectory extends Directory implements Serializable {
036:
037: private static final long serialVersionUID = 1l;
038:
039: HashMap fileMap = new HashMap();
040: long sizeInBytes = 0;
041:
042: // *****
043: // Lock acquisition sequence: RAMDirectory, then RAMFile
044: // *****
045:
046: /** Constructs an empty {@link Directory}. */
047: public RAMDirectory() {
048: setLockFactory(new SingleInstanceLockFactory());
049: }
050:
051: /**
052: * Creates a new <code>RAMDirectory</code> instance from a different
053: * <code>Directory</code> implementation. This can be used to load
054: * a disk-based index into memory.
055: * <P>
056: * This should be used only with indices that can fit into memory.
057: * <P>
058: * Note that the resulting <code>RAMDirectory</code> instance is fully
059: * independent from the original <code>Directory</code> (it is a
060: * complete copy). Any subsequent changes to the
061: * original <code>Directory</code> will not be visible in the
062: * <code>RAMDirectory</code> instance.
063: *
064: * @param dir a <code>Directory</code> value
065: * @exception IOException if an error occurs
066: */
067: public RAMDirectory(Directory dir) throws IOException {
068: this (dir, false);
069: }
070:
071: private RAMDirectory(Directory dir, boolean closeDir)
072: throws IOException {
073: this ();
074: Directory.copy(dir, this , closeDir);
075: }
076:
077: /**
078: * Creates a new <code>RAMDirectory</code> instance from the {@link FSDirectory}.
079: *
080: * @param dir a <code>File</code> specifying the index directory
081: *
082: * @see #RAMDirectory(Directory)
083: */
084: public RAMDirectory(File dir) throws IOException {
085: this (FSDirectory.getDirectory(dir), true);
086: }
087:
088: /**
089: * Creates a new <code>RAMDirectory</code> instance from the {@link FSDirectory}.
090: *
091: * @param dir a <code>String</code> specifying the full index directory path
092: *
093: * @see #RAMDirectory(Directory)
094: */
095: public RAMDirectory(String dir) throws IOException {
096: this (FSDirectory.getDirectory(dir), true);
097: }
098:
099: /** Returns an array of strings, one for each file in the directory. */
100: public synchronized final String[] list() {
101: ensureOpen();
102: Set fileNames = fileMap.keySet();
103: String[] result = new String[fileNames.size()];
104: int i = 0;
105: Iterator it = fileNames.iterator();
106: while (it.hasNext())
107: result[i++] = (String) it.next();
108: return result;
109: }
110:
111: /** Returns true iff the named file exists in this directory. */
112: public final boolean fileExists(String name) {
113: ensureOpen();
114: RAMFile file;
115: synchronized (this ) {
116: file = (RAMFile) fileMap.get(name);
117: }
118: return file != null;
119: }
120:
121: /** Returns the time the named file was last modified.
122: * @throws IOException if the file does not exist
123: */
124: public final long fileModified(String name) throws IOException {
125: ensureOpen();
126: RAMFile file;
127: synchronized (this ) {
128: file = (RAMFile) fileMap.get(name);
129: }
130: if (file == null)
131: throw new FileNotFoundException(name);
132: return file.getLastModified();
133: }
134:
135: /** Set the modified time of an existing file to now.
136: * @throws IOException if the file does not exist
137: */
138: public void touchFile(String name) throws IOException {
139: ensureOpen();
140: RAMFile file;
141: synchronized (this ) {
142: file = (RAMFile) fileMap.get(name);
143: }
144: if (file == null)
145: throw new FileNotFoundException(name);
146:
147: long ts2, ts1 = System.currentTimeMillis();
148: do {
149: try {
150: Thread.sleep(0, 1);
151: } catch (InterruptedException e) {
152: }
153: ts2 = System.currentTimeMillis();
154: } while (ts1 == ts2);
155:
156: file.setLastModified(ts2);
157: }
158:
159: /** Returns the length in bytes of a file in the directory.
160: * @throws IOException if the file does not exist
161: */
162: public final long fileLength(String name) throws IOException {
163: ensureOpen();
164: RAMFile file;
165: synchronized (this ) {
166: file = (RAMFile) fileMap.get(name);
167: }
168: if (file == null)
169: throw new FileNotFoundException(name);
170: return file.getLength();
171: }
172:
173: /** Return total size in bytes of all files in this
174: * directory. This is currently quantized to
175: * RAMOutputStream.BUFFER_SIZE. */
176: public synchronized final long sizeInBytes() {
177: ensureOpen();
178: return sizeInBytes;
179: }
180:
181: /** Removes an existing file in the directory.
182: * @throws IOException if the file does not exist
183: */
184: public synchronized void deleteFile(String name) throws IOException {
185: ensureOpen();
186: RAMFile file = (RAMFile) fileMap.get(name);
187: if (file != null) {
188: fileMap.remove(name);
189: file.directory = null;
190: sizeInBytes -= file.sizeInBytes; // updates to RAMFile.sizeInBytes synchronized on directory
191: } else
192: throw new FileNotFoundException(name);
193: }
194:
195: /** Renames an existing file in the directory.
196: * @throws FileNotFoundException if from does not exist
197: * @deprecated
198: */
199: public synchronized final void renameFile(String from, String to)
200: throws IOException {
201: ensureOpen();
202: RAMFile fromFile = (RAMFile) fileMap.get(from);
203: if (fromFile == null)
204: throw new FileNotFoundException(from);
205: RAMFile toFile = (RAMFile) fileMap.get(to);
206: if (toFile != null) {
207: sizeInBytes -= toFile.sizeInBytes; // updates to RAMFile.sizeInBytes synchronized on directory
208: toFile.directory = null;
209: }
210: fileMap.remove(from);
211: fileMap.put(to, fromFile);
212: }
213:
214: /** Creates a new, empty file in the directory with the given name. Returns a stream writing this file. */
215: public IndexOutput createOutput(String name) throws IOException {
216: ensureOpen();
217: RAMFile file = new RAMFile(this );
218: synchronized (this ) {
219: RAMFile existing = (RAMFile) fileMap.get(name);
220: if (existing != null) {
221: sizeInBytes -= existing.sizeInBytes;
222: existing.directory = null;
223: }
224: fileMap.put(name, file);
225: }
226: return new RAMOutputStream(file);
227: }
228:
229: /** Returns a stream reading an existing file. */
230: public IndexInput openInput(String name) throws IOException {
231: ensureOpen();
232: RAMFile file;
233: synchronized (this ) {
234: file = (RAMFile) fileMap.get(name);
235: }
236: if (file == null)
237: throw new FileNotFoundException(name);
238: return new RAMInputStream(file);
239: }
240:
241: /** Closes the store to future operations, releasing associated memory. */
242: public void close() {
243: fileMap = null;
244: }
245:
246: /**
247: * @throws AlreadyClosedException if this IndexReader is closed
248: */
249: protected final void ensureOpen() throws AlreadyClosedException {
250: if (fileMap == null) {
251: throw new AlreadyClosedException(
252: "this RAMDirectory is closed");
253: }
254: }
255: }
|