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.
20 import java.io.IOException;
21 import java.io.FileNotFoundException;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.List;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.atomic.AtomicLong;
30 import org.apache.lucene.index.IndexFileNameFilter;
31 import org.apache.lucene.util.ThreadInterruptedException;
34 * A memory-resident {@link Directory} implementation. Locking
35 * implementation is by default the {@link SingleInstanceLockFactory}
36 * but can be changed with {@link #setLockFactory}.
38 public class RAMDirectory extends Directory implements Serializable {
40 private static final long serialVersionUID = 1l;
42 protected final Map<String,RAMFile> fileMap = new ConcurrentHashMap<String,RAMFile>();
43 protected final AtomicLong sizeInBytes = new AtomicLong();
46 // Lock acquisition sequence: RAMDirectory, then RAMFile
49 /** Constructs an empty {@link Directory}. */
50 public RAMDirectory() {
52 setLockFactory(new SingleInstanceLockFactory());
53 } catch (IOException e) {
59 * Creates a new <code>RAMDirectory</code> instance from a different
60 * <code>Directory</code> implementation. This can be used to load
61 * a disk-based index into memory.
63 * This should be used only with indices that can fit into memory.
65 * Note that the resulting <code>RAMDirectory</code> instance is fully
66 * independent from the original <code>Directory</code> (it is a
67 * complete copy). Any subsequent changes to the
68 * original <code>Directory</code> will not be visible in the
69 * <code>RAMDirectory</code> instance.
71 * @param dir a <code>Directory</code> value
72 * @exception IOException if an error occurs
74 public RAMDirectory(Directory dir) throws IOException {
78 private RAMDirectory(Directory dir, boolean closeDir) throws IOException {
81 IndexFileNameFilter filter = IndexFileNameFilter.getFilter();
82 for (String file : dir.listAll()) {
83 if (filter.accept(null, file)) {
84 dir.copy(this, file, file);
93 public final String[] listAll() {
95 // NOTE: fileMap.keySet().toArray(new String[0]) is broken in non Sun JDKs,
96 // and the code below is resilient to map changes during the array population.
97 Set<String> fileNames = fileMap.keySet();
98 List<String> names = new ArrayList<String>(fileNames.size());
99 for (String name : fileNames) names.add(name);
100 return names.toArray(new String[names.size()]);
103 /** Returns true iff the named file exists in this directory. */
105 public final boolean fileExists(String name) {
107 return fileMap.containsKey(name);
110 /** Returns the time the named file was last modified.
111 * @throws IOException if the file does not exist
114 public final long fileModified(String name) throws IOException {
116 RAMFile file = fileMap.get(name);
118 throw new FileNotFoundException(name);
120 return file.getLastModified();
123 /** Set the modified time of an existing file to now.
124 * @throws IOException if the file does not exist
125 * @deprecated Lucene never uses this API; it will be
129 public void touchFile(String name) throws IOException {
131 RAMFile file = fileMap.get(name);
133 throw new FileNotFoundException(name);
136 long ts2, ts1 = System.currentTimeMillis();
140 } catch (InterruptedException ie) {
141 throw new ThreadInterruptedException(ie);
143 ts2 = System.currentTimeMillis();
146 file.setLastModified(ts2);
149 /** Returns the length in bytes of a file in the directory.
150 * @throws IOException if the file does not exist
153 public final long fileLength(String name) throws IOException {
155 RAMFile file = fileMap.get(name);
157 throw new FileNotFoundException(name);
159 return file.getLength();
163 * Return total size in bytes of all files in this directory. This is
164 * currently quantized to RAMOutputStream.BUFFER_SIZE.
166 public final long sizeInBytes() {
168 return sizeInBytes.get();
171 /** Removes an existing file in the directory.
172 * @throws IOException if the file does not exist
175 public void deleteFile(String name) throws IOException {
177 RAMFile file = fileMap.remove(name);
179 file.directory = null;
180 sizeInBytes.addAndGet(-file.sizeInBytes);
182 throw new FileNotFoundException(name);
186 /** Creates a new, empty file in the directory with the given name. Returns a stream writing this file. */
188 public IndexOutput createOutput(String name) throws IOException {
190 RAMFile file = newRAMFile();
191 RAMFile existing = fileMap.remove(name);
192 if (existing != null) {
193 sizeInBytes.addAndGet(-existing.sizeInBytes);
194 existing.directory = null;
196 fileMap.put(name, file);
197 return new RAMOutputStream(file);
201 * Returns a new {@link RAMFile} for storing data. This method can be
202 * overridden to return different {@link RAMFile} impls, that e.g. override
203 * {@link RAMFile#newBuffer(int)}.
205 protected RAMFile newRAMFile() {
206 return new RAMFile(this);
209 /** Returns a stream reading an existing file. */
211 public IndexInput openInput(String name) throws IOException {
213 RAMFile file = fileMap.get(name);
215 throw new FileNotFoundException(name);
217 return new RAMInputStream(name, file);
220 /** Closes the store to future operations, releasing associated memory. */
222 public void close() {