001: /*
002:
003: Derby - Class org.apache.derby.impl.io.DirFile4
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.io;
023:
024: import org.apache.derby.iapi.services.sanity.SanityManager;
025: import org.apache.derby.io.StorageFile;
026: import org.apache.derby.io.StorageRandomAccessFile;
027:
028: import java.io.FileNotFoundException;
029: import java.io.FileOutputStream;
030: import java.io.OutputStream;
031: import java.io.File;
032: import java.io.IOException;
033: import java.io.RandomAccessFile;
034: import java.nio.channels.FileChannel;
035: import java.nio.channels.FileLock;
036:
037: /**
038: * This class implements the StorageFile interface using features of Java 1.4 not available in earlier
039: * versions of Java.
040: */
041: class DirFile4 extends DirFile {
042:
043: private RandomAccessFile lockFileOpen;
044: private FileChannel lockFileChannel;
045: private FileLock dbLock;
046:
047: private final boolean rwsOK;
048:
049: /**
050: * Construct a DirFile from a path name.
051: *
052: * @param path The path name.
053: */
054: DirFile4(String path, boolean rwsOK) {
055: super (path);
056: this .rwsOK = rwsOK;
057: }
058:
059: /**
060: * Construct a DirFile from a directory name and a file name.
061: *
062: * @param directoryName The directory part of the path name.
063: * @param fileName The name of the file within the directory.
064: */
065: DirFile4(String directoryName, String fileName, boolean rwsOK) {
066: super (directoryName, fileName);
067: this .rwsOK = rwsOK;
068: }
069:
070: /**
071: * Construct a DirFile from a directory name and a file name.
072: *
073: * @param directoryName The directory part of the path name.
074: * @param fileName The name of the file within the directory.
075: */
076: DirFile4(DirFile directoryName, String fileName, boolean rwsOK) {
077: super (directoryName, fileName);
078: this .rwsOK = rwsOK;
079: }
080:
081: /**
082: * Get the name of the parent directory if this name includes a parent.
083: *
084: * @return An StorageFile denoting the parent directory of this StorageFile, if it has a parent, null if
085: * it does not have a parent.
086: */
087: public StorageFile getParentDir() {
088: String parent = getParent();
089: if (parent == null)
090: return null;
091: return new DirFile4(parent, rwsOK);
092: }
093:
094: /**
095: * Creates an output stream from a file name.
096: *
097: * @param append If true then data will be appended to the end of the file, if it already exists.
098: * If false and a normal file already exists with this name the file will first be truncated
099: * to zero length.
100: *
101: * @return an output stream suitable for writing to the file.
102: *
103: * @exception FileNotFoundException if the file exists but is a directory
104: * rather than a regular file, does not exist but cannot be created, or
105: * cannot be opened for any other reason.
106: */
107: public OutputStream getOutputStream(final boolean append)
108: throws FileNotFoundException {
109: return new FileOutputStream((File) this , append);
110: }
111:
112: public synchronized int getExclusiveFileLock() {
113: boolean validExclusiveLock = false;
114: int status;
115:
116: /*
117: ** There can be a scenario where there is some other JVM that is before jkdk1.4
118: ** had booted the system and jdk1.4 trying to boot it, in this case we will get the
119: ** Exclusive Lock even though some other JVM has already booted the database. But
120: ** the lock is not a reliable one , so we should still throw the warning.
121: ** The Way we identify this case is if "dbex.lck" file size is differen
122: ** for pre jdk1.4 jvms and jdk1.4 or above.
123: ** Zero size "dbex.lck" file is created by a jvm i.e before jdk1.4 and
124: ** File created by jdk1.4 or above writes EXCLUSIVE_FILE_LOCK value into the file.
125: ** If we are unable to acquire the lock means other JVM that
126: ** currently booted the system is also JDK1.4 or above;
127: ** In this case we could confidently throw a exception instead of
128: ** of a warning.
129: **/
130:
131: try {
132: //create the file that us used to acquire exclusive lock if it does not exists.
133: if (createNewFile()) {
134: validExclusiveLock = true;
135: } else {
136: if (length() > 0)
137: validExclusiveLock = true;
138: }
139:
140: //If we can acquire a reliable exclusive lock , try to get it.
141: if (validExclusiveLock) {
142: lockFileOpen = new RandomAccessFile((File) this , "rw");
143: lockFileChannel = lockFileOpen.getChannel();
144: dbLock = lockFileChannel.tryLock();
145: if (dbLock == null) {
146: lockFileChannel.close();
147: lockFileChannel = null;
148: lockFileOpen.close();
149: lockFileOpen = null;
150: status = EXCLUSIVE_FILE_LOCK_NOT_AVAILABLE;
151: } else {
152: lockFileOpen.writeInt(EXCLUSIVE_FILE_LOCK);
153: lockFileChannel.force(true);
154: status = EXCLUSIVE_FILE_LOCK;
155: }
156: } else {
157: status = NO_FILE_LOCK_SUPPORT;
158: }
159:
160: } catch (IOException ioe) {
161: // do nothing - it may be read only medium, who knows what the
162: // problem is
163:
164: //release all the possible resource we created in this functions.
165: releaseExclusiveFileLock();
166: status = NO_FILE_LOCK_SUPPORT;
167: if (SanityManager.DEBUG) {
168: SanityManager
169: .THROWASSERT("Unable to Acquire Exclusive Lock on "
170: + getPath());
171: }
172: }
173:
174: return status;
175: } // end of getExclusiveFileLock
176:
177: public synchronized void releaseExclusiveFileLock() {
178: try {
179: if (dbLock != null) {
180: dbLock.release();
181: dbLock = null;
182: }
183:
184: if (lockFileChannel != null) {
185: lockFileChannel.close();
186: lockFileChannel = null;
187: }
188:
189: if (lockFileOpen != null) {
190: lockFileOpen.close();
191: lockFileOpen = null;
192: }
193:
194: //delete the exclusive lock file name.
195: super .releaseExclusiveFileLock();
196: } catch (IOException ioe) {
197: // do nothing - it may be read only medium, who knows what the
198: // problem is
199: }
200: } // End of releaseExclusiveFileLock
201:
202: /**
203: * Get a random access (read/write) file.
204: *
205: * @param mode "r", "rw", "rws", or "rwd". The "rws" and "rwd" modes specify
206: * that the data is to be written to persistent store, consistent with the
207: * java.io.RandomAccessFile class ("synchronized" with the persistent
208: * storage, in the file system meaning of the word "synchronized"). However
209: * the implementation is not required to implement the "rws" or "rwd"
210: * modes. The implementation may treat "rws" and "rwd" as "rw". It is up to
211: * the user of this interface to call the StorageRandomAccessFile.sync
212: * method. If the "rws" or "rwd" modes are supported and the
213: * RandomAccessFile was opened in "rws" or "rwd" mode then the
214: * implementation of StorageRandomAccessFile.sync need not do anything.
215: *
216: * @return an object that can be used for random access to the file.
217: *
218: * @exception IllegalArgumentException if the mode argument is not equal to one of "r", "rw", "rws", or "rwd".
219: * @exception FileNotFoundException if the file exists but is a directory rather than a regular
220: * file, or cannot be opened or created for any other reason .
221: */
222: public StorageRandomAccessFile getRandomAccessFile(String mode)
223: throws FileNotFoundException {
224: // Assume that modes "rws" and "rwd" are not supported.
225: if (!rwsOK && ("rws".equals(mode) || "rwd".equals(mode)))
226: mode = "rw";
227: return new DirRandomAccessFile4((File) this , mode);
228: } // end of getRandomAccessFile
229: }
|