1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.io.DirFile4 |
4 | |
5 | Copyright 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | 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 | |
21 | package org.apache.derby.impl.io; |
22 | |
23 | import org.apache.derby.iapi.services.sanity.SanityManager; |
24 | import org.apache.derby.io.StorageFile; |
25 | import org.apache.derby.io.StorageRandomAccessFile; |
26 | |
27 | import java.io.FileNotFoundException; |
28 | import java.io.FileOutputStream; |
29 | import java.io.OutputStream; |
30 | import java.io.File; |
31 | import java.io.IOException; |
32 | import java.io.RandomAccessFile; |
33 | import java.nio.channels.FileChannel; |
34 | import java.nio.channels.FileLock; |
35 | |
36 | /** |
37 | * This class implements the StorageFile interface using features of Java 1.4 not available in earlier |
38 | * versions of Java. |
39 | */ |
40 | class DirFile4 extends DirFile |
41 | { |
42 | |
43 | private RandomAccessFile lockFileOpen; |
44 | private FileChannel lockFileChannel; |
45 | private FileLock dbLock; |
46 | |
47 | private final boolean rwsOK; |
48 | |
49 | /** |
50 | * Construct a DirFile from a path name. |
51 | * |
52 | * @param path The path name. |
53 | */ |
54 | DirFile4( String path, boolean rwsOK) |
55 | { |
56 | super( path); |
57 | this.rwsOK = rwsOK; |
58 | } |
59 | |
60 | /** |
61 | * Construct a DirFile from a directory name and a file name. |
62 | * |
63 | * @param directoryName The directory part of the path name. |
64 | * @param fileName The name of the file within the directory. |
65 | */ |
66 | DirFile4( String directoryName, String fileName, boolean rwsOK) |
67 | { |
68 | super( directoryName, fileName); |
69 | this.rwsOK = rwsOK; |
70 | } |
71 | |
72 | /** |
73 | * Construct a DirFile from a directory name and a file name. |
74 | * |
75 | * @param directoryName The directory part of the path name. |
76 | * @param fileName The name of the file within the directory. |
77 | */ |
78 | DirFile4( DirFile directoryName, String fileName, boolean rwsOK) |
79 | { |
80 | super( directoryName, fileName); |
81 | this.rwsOK = rwsOK; |
82 | } |
83 | |
84 | /** |
85 | * Get the name of the parent directory if this name includes a parent. |
86 | * |
87 | * @return An StorageFile denoting the parent directory of this StorageFile, if it has a parent, null if |
88 | * it does not have a parent. |
89 | */ |
90 | public StorageFile getParentDir() |
91 | { |
92 | String parent = getParent(); |
93 | if( parent == null) |
94 | return null; |
95 | return new DirFile4( parent, rwsOK); |
96 | } |
97 | |
98 | /** |
99 | * Creates an output stream from a file name. |
100 | * |
101 | * @param append If true then data will be appended to the end of the file, if it already exists. |
102 | * If false and a normal file already exists with this name the file will first be truncated |
103 | * to zero length. |
104 | * |
105 | * @return an output stream suitable for writing to the file. |
106 | * |
107 | * @exception FileNotFoundException if the file exists but is a directory |
108 | * rather than a regular file, does not exist but cannot be created, or |
109 | * cannot be opened for any other reason. |
110 | */ |
111 | public OutputStream getOutputStream( final boolean append) throws FileNotFoundException |
112 | { |
113 | return new FileOutputStream( (File) this, append); |
114 | } |
115 | |
116 | public synchronized int getExclusiveFileLock() |
117 | { |
118 | boolean validExclusiveLock = false; |
119 | int status; |
120 | |
121 | /* |
122 | ** There can be a scenario where there is some other JVM that is before jkdk1.4 |
123 | ** had booted the system and jdk1.4 trying to boot it, in this case we will get the |
124 | ** Exclusive Lock even though some other JVM has already booted the database. But |
125 | ** the lock is not a reliable one , so we should still throw the warning. |
126 | ** The Way we identify this case is if "dbex.lck" file size is differen |
127 | ** for pre jdk1.4 jvms and jdk1.4 or above. |
128 | ** Zero size "dbex.lck" file is created by a jvm i.e before jdk1.4 and |
129 | ** File created by jdk1.4 or above writes EXCLUSIVE_FILE_LOCK value into the file. |
130 | ** If we are unable to acquire the lock means other JVM that |
131 | ** currently booted the system is also JDK1.4 or above; |
132 | ** In this case we could confidently throw a exception instead of |
133 | ** of a warning. |
134 | **/ |
135 | |
136 | try |
137 | { |
138 | //create the file that us used to acquire exclusive lock if it does not exists. |
139 | if(createNewFile()) |
140 | { |
141 | validExclusiveLock = true; |
142 | } |
143 | else |
144 | { |
145 | if(length() > 0) |
146 | validExclusiveLock = true; |
147 | } |
148 | |
149 | //If we can acquire a reliable exclusive lock , try to get it. |
150 | if(validExclusiveLock) |
151 | { |
152 | lockFileOpen = new RandomAccessFile((File) this, "rw"); |
153 | lockFileChannel = lockFileOpen.getChannel(); |
154 | dbLock =lockFileChannel.tryLock(); |
155 | if(dbLock == null) |
156 | { |
157 | lockFileChannel.close(); |
158 | lockFileChannel=null; |
159 | lockFileOpen.close(); |
160 | lockFileOpen = null; |
161 | status = EXCLUSIVE_FILE_LOCK_NOT_AVAILABLE; |
162 | } |
163 | else |
164 | { |
165 | lockFileOpen.writeInt(EXCLUSIVE_FILE_LOCK); |
166 | lockFileChannel.force(true); |
167 | status = EXCLUSIVE_FILE_LOCK; |
168 | } |
169 | } |
170 | else |
171 | { |
172 | status = NO_FILE_LOCK_SUPPORT; |
173 | } |
174 | |
175 | }catch(IOException ioe) |
176 | { |
177 | // do nothing - it may be read only medium, who knows what the |
178 | // problem is |
179 | |
180 | //release all the possible resource we created in this functions. |
181 | releaseExclusiveFileLock(); |
182 | status = NO_FILE_LOCK_SUPPORT; |
183 | if (SanityManager.DEBUG) |
184 | { |
185 | SanityManager.THROWASSERT("Unable to Acquire Exclusive Lock on " |
186 | + getPath()); |
187 | } |
188 | } |
189 | |
190 | return status; |
191 | } // end of getExclusiveFileLock |
192 | |
193 | public synchronized void releaseExclusiveFileLock() |
194 | { |
195 | try |
196 | { |
197 | if(dbLock!=null) |
198 | { |
199 | dbLock.release(); |
200 | dbLock =null; |
201 | } |
202 | |
203 | if(lockFileChannel !=null) |
204 | { |
205 | lockFileChannel.close(); |
206 | lockFileChannel = null; |
207 | } |
208 | |
209 | if(lockFileOpen !=null) |
210 | { |
211 | lockFileOpen.close(); |
212 | lockFileOpen = null; |
213 | } |
214 | |
215 | //delete the exclusive lock file name. |
216 | super.releaseExclusiveFileLock(); |
217 | }catch (IOException ioe) |
218 | { |
219 | // do nothing - it may be read only medium, who knows what the |
220 | // problem is |
221 | } |
222 | } // End of releaseExclusiveFileLock |
223 | |
224 | /** |
225 | * Get a random access (read/write) file. |
226 | * |
227 | * @param mode "r", "rw", "rws", or "rwd". The "rws" and "rwd" modes specify |
228 | * that the data is to be written to persistent store, consistent with the |
229 | * java.io.RandomAccessFile class ("synchronized" with the persistent |
230 | * storage, in the file system meaning of the word "synchronized"). However |
231 | * the implementation is not required to implement the "rws" or "rwd" |
232 | * modes. The implementation may treat "rws" and "rwd" as "rw". It is up to |
233 | * the user of this interface to call the StorageRandomAccessFile.sync |
234 | * method. If the "rws" or "rwd" modes are supported and the |
235 | * RandomAccessFile was opened in "rws" or "rwd" mode then the |
236 | * implementation of StorageRandomAccessFile.sync need not do anything. |
237 | * |
238 | * @return an object that can be used for random access to the file. |
239 | * |
240 | * @exception IllegalArgumentException if the mode argument is not equal to one of "r", "rw". |
241 | * @exception FileNotFoundException if the file exists but is a directory rather than a regular |
242 | * file, or cannot be opened or created for any other reason . |
243 | */ |
244 | public StorageRandomAccessFile getRandomAccessFile( String mode) throws FileNotFoundException |
245 | { |
246 | // Assume that modes "rws" and "rwd" are not supported. |
247 | if(!rwsOK && "rws".equals( mode) || "rwd".equals( mode)) |
248 | mode = "rw"; |
249 | return new DirRandomAccessFile4( (File) this, mode); |
250 | } // end of getRandomAccessFile |
251 | } |