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
22 /** A Directory is a flat list of files. Files may be written once, when they
23 * are created. Once a file is created it may only be opened for read, or
24 * deleted. Random access is permitted both when reading and writing.
25 *
26 * <p> Java's i/o APIs not used directly, but rather all i/o is
27 * through this API. This permits things such as: <ul>
28 * <li> implementation of RAM-based indices;
29 * <li> implementation indices stored in a database, via JDBC;
30 * <li> implementation of an index as a single file;
31 * </ul>
32 *
33 * Directory locking is implemented by an instance of {@link
34 * LockFactory}, and can be changed for each Directory
35 * instance using {@link #setLockFactory}.
36 *
37 */
38 public abstract class Directory {
39
40 volatile boolean isOpen = true;
41
42 /** Holds the LockFactory instance (implements locking for
43 * this Directory instance). */
44 protected LockFactory lockFactory;
45
46 /** Returns an array of strings, one for each file in the
47 * directory. This method may return null (for example for
48 * {@link FSDirectory} if the underlying directory doesn't
49 * exist in the filesystem or there are permissions
50 * problems).*/
51 public abstract String[] list()
52 throws IOException;
53
54 /** Returns true iff a file with the given name exists. */
55 public abstract boolean fileExists(String name)
56 throws IOException;
57
58 /** Returns the time the named file was last modified. */
59 public abstract long fileModified(String name)
60 throws IOException;
61
62 /** Set the modified time of an existing file to now. */
63 public abstract void touchFile(String name)
64 throws IOException;
65
66 /** Removes an existing file in the directory. */
67 public abstract void deleteFile(String name)
68 throws IOException;
69
70 /** Renames an existing file in the directory.
71 * If a file already exists with the new name, then it is replaced.
72 * This replacement is not guaranteed to be atomic.
73 * @deprecated
74 */
75 public abstract void renameFile(String from, String to)
76 throws IOException;
77
78 /** Returns the length of a file in the directory. */
79 public abstract long fileLength(String name)
80 throws IOException;
81
82
83 /** Creates a new, empty file in the directory with the given name.
84 Returns a stream writing this file. */
85 public abstract IndexOutput createOutput(String name) throws IOException;
86
87 /** Ensure that any writes to this file are moved to
88 * stable storage. Lucene uses this to properly commit
89 * changes to the index, to prevent a machine/OS crash
90 * from corrupting the index. */
91 public void sync(String name) throws IOException {}
92
93 /** Returns a stream reading an existing file. */
94 public abstract IndexInput openInput(String name)
95 throws IOException;
96
97 /** Returns a stream reading an existing file, with the
98 * specified read buffer size. The particular Directory
99 * implementation may ignore the buffer size. Currently
100 * the only Directory implementations that respect this
101 * parameter are {@link FSDirectory} and {@link
102 * org.apache.lucene.index.CompoundFileReader}.
103 */
104 public IndexInput openInput(String name, int bufferSize) throws IOException {
105 return openInput(name);
106 }
107
108 /** Construct a {@link Lock}.
109 * @param name the name of the lock file
110 */
111 public Lock makeLock(String name) {
112 return lockFactory.makeLock(name);
113 }
114 /**
115 * Attempt to clear (forcefully unlock and remove) the
116 * specified lock. Only call this at a time when you are
117 * certain this lock is no longer in use.
118 * @param name name of the lock to be cleared.
119 */
120 public void clearLock(String name) throws IOException {
121 if (lockFactory != null) {
122 lockFactory.clearLock(name);
123 }
124 }
125
126 /** Closes the store. */
127 public abstract void close()
128 throws IOException;
129
130 /**
131 * Set the LockFactory that this Directory instance should
132 * use for its locking implementation. Each * instance of
133 * LockFactory should only be used for one directory (ie,
134 * do not share a single instance across multiple
135 * Directories).
136 *
137 * @param lockFactory instance of {@link LockFactory}.
138 */
139 public void setLockFactory(LockFactory lockFactory) {
140 this.lockFactory = lockFactory;
141 lockFactory.setLockPrefix(this.getLockID());
142 }
143
144 /**
145 * Get the LockFactory that this Directory instance is
146 * using for its locking implementation. Note that this
147 * may be null for Directory implementations that provide
148 * their own locking implementation.
149 */
150 public LockFactory getLockFactory() {
151 return this.lockFactory;
152 }
153
154 /**
155 * Return a string identifier that uniquely differentiates
156 * this Directory instance from other Directory instances.
157 * This ID should be the same if two Directory instances
158 * (even in different JVMs and/or on different machines)
159 * are considered "the same index". This is how locking
160 * "scopes" to the right index.
161 */
162 public String getLockID() {
163 return this.toString();
164 }
165
166 /**
167 * Copy contents of a directory src to a directory dest.
168 * If a file in src already exists in dest then the
169 * one in dest will be blindly overwritten.
170 *
171 * @param src source directory
172 * @param dest destination directory
173 * @param closeDirSrc if <code>true</code>, call {@link #close()} method on source directory
174 * @throws IOException
175 */
176 public static void copy(Directory src, Directory dest, boolean closeDirSrc) throws IOException {
177 final String[] files = src.list();
178
179 if (files == null)
180 throw new IOException("cannot read directory " + src + ": list() returned null");
181
182 byte[] buf = new byte[BufferedIndexOutput.BUFFER_SIZE];
183 for (int i = 0; i < files.length; i++) {
184 IndexOutput os = null;
185 IndexInput is = null;
186 try {
187 // create file in dest directory
188 os = dest.createOutput(files[i]);
189 // read current file
190 is = src.openInput(files[i]);
191 // and copy to dest directory
192 long len = is.length();
193 long readCount = 0;
194 while (readCount < len) {
195 int toRead = readCount + BufferedIndexOutput.BUFFER_SIZE > len ? (int)(len - readCount) : BufferedIndexOutput.BUFFER_SIZE;
196 is.readBytes(buf, 0, toRead);
197 os.writeBytes(buf, toRead);
198 readCount += toRead;
199 }
200 } finally {
201 // graceful cleanup
202 try {
203 if (os != null)
204 os.close();
205 } finally {
206 if (is != null)
207 is.close();
208 }
209 }
210 }
211 if(closeDirSrc)
212 src.close();
213 }
214
215 /**
216 * @throws AlreadyClosedException if this Directory is closed
217 */
218 protected final void ensureOpen() throws AlreadyClosedException {
219 if (!isOpen)
220 throw new AlreadyClosedException("this Directory is closed");
221 }
222 }