pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / store / RAMDirectory.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.IOException;
21 import java.io.FileNotFoundException;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.atomic.AtomicLong;
29
30 import org.apache.lucene.index.IndexFileNameFilter;
31 import org.apache.lucene.util.ThreadInterruptedException;
32
33 /**
34  * A memory-resident {@link Directory} implementation.  Locking
35  * implementation is by default the {@link SingleInstanceLockFactory}
36  * but can be changed with {@link #setLockFactory}.
37  */
38 public class RAMDirectory extends Directory implements Serializable {
39
40   private static final long serialVersionUID = 1l;
41
42   protected final Map<String,RAMFile> fileMap = new ConcurrentHashMap<String,RAMFile>();
43   protected final AtomicLong sizeInBytes = new AtomicLong();
44   
45   // *****
46   // Lock acquisition sequence:  RAMDirectory, then RAMFile
47   // *****
48
49   /** Constructs an empty {@link Directory}. */
50   public RAMDirectory() {
51     try {
52       setLockFactory(new SingleInstanceLockFactory());
53     } catch (IOException e) {
54       // Cannot happen
55     }
56   }
57
58   /**
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.
62    * <P>
63    * This should be used only with indices that can fit into memory.
64    * <P>
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.
70    *
71    * @param dir a <code>Directory</code> value
72    * @exception IOException if an error occurs
73    */
74   public RAMDirectory(Directory dir) throws IOException {
75     this(dir, false);
76   }
77   
78   private RAMDirectory(Directory dir, boolean closeDir) throws IOException {
79     this();
80
81     IndexFileNameFilter filter = IndexFileNameFilter.getFilter();
82     for (String file : dir.listAll()) {
83       if (filter.accept(null, file)) {
84         dir.copy(this, file, file);
85       }
86     }
87     if (closeDir) {
88       dir.close();
89     }
90   }
91
92   @Override
93   public final String[] listAll() {
94     ensureOpen();
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()]);
101   }
102
103   /** Returns true iff the named file exists in this directory. */
104   @Override
105   public final boolean fileExists(String name) {
106     ensureOpen();
107     return fileMap.containsKey(name);
108   }
109
110   /** Returns the time the named file was last modified.
111    * @throws IOException if the file does not exist
112    */
113   @Override
114   public final long fileModified(String name) throws IOException {
115     ensureOpen();
116     RAMFile file = fileMap.get(name);
117     if (file == null) {
118       throw new FileNotFoundException(name);
119     }
120     return file.getLastModified();
121   }
122
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
126    *  removed in 4.0. */
127   @Override
128   @Deprecated
129   public void touchFile(String name) throws IOException {
130     ensureOpen();
131     RAMFile file = fileMap.get(name);
132     if (file == null) {
133       throw new FileNotFoundException(name);
134     }
135     
136     long ts2, ts1 = System.currentTimeMillis();
137     do {
138       try {
139         Thread.sleep(0, 1);
140       } catch (InterruptedException ie) {
141         throw new ThreadInterruptedException(ie);
142       }
143       ts2 = System.currentTimeMillis();
144     } while(ts1 == ts2);
145     
146     file.setLastModified(ts2);
147   }
148
149   /** Returns the length in bytes of a file in the directory.
150    * @throws IOException if the file does not exist
151    */
152   @Override
153   public final long fileLength(String name) throws IOException {
154     ensureOpen();
155     RAMFile file = fileMap.get(name);
156     if (file == null) {
157       throw new FileNotFoundException(name);
158     }
159     return file.getLength();
160   }
161   
162   /**
163    * Return total size in bytes of all files in this directory. This is
164    * currently quantized to RAMOutputStream.BUFFER_SIZE.
165    */
166   public final long sizeInBytes() {
167     ensureOpen();
168     return sizeInBytes.get();
169   }
170   
171   /** Removes an existing file in the directory.
172    * @throws IOException if the file does not exist
173    */
174   @Override
175   public void deleteFile(String name) throws IOException {
176     ensureOpen();
177     RAMFile file = fileMap.remove(name);
178     if (file != null) {
179       file.directory = null;
180       sizeInBytes.addAndGet(-file.sizeInBytes);
181     } else {
182       throw new FileNotFoundException(name);
183     }
184   }
185
186   /** Creates a new, empty file in the directory with the given name. Returns a stream writing this file. */
187   @Override
188   public IndexOutput createOutput(String name) throws IOException {
189     ensureOpen();
190     RAMFile file = newRAMFile();
191     RAMFile existing = fileMap.remove(name);
192     if (existing != null) {
193       sizeInBytes.addAndGet(-existing.sizeInBytes);
194       existing.directory = null;
195     }
196     fileMap.put(name, file);
197     return new RAMOutputStream(file);
198   }
199
200   /**
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)}.
204    */
205   protected RAMFile newRAMFile() {
206     return new RAMFile(this);
207   }
208
209   /** Returns a stream reading an existing file. */
210   @Override
211   public IndexInput openInput(String name) throws IOException {
212     ensureOpen();
213     RAMFile file = fileMap.get(name);
214     if (file == null) {
215       throw new FileNotFoundException(name);
216     }
217     return new RAMInputStream(name, file);
218   }
219
220   /** Closes the store to future operations, releasing associated memory. */
221   @Override
222   public void close() {
223     isOpen = false;
224     fileMap.clear();
225   }
226 }