📄 niolockfile.java
字号:
/* Copyright (c) 2001-2008, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */package org.hsqldb.persist;import java.io.RandomAccessFile;import java.nio.channels.FileLock;/** * LockFile variant that capitalizes upon the availability of * {@link java.nio.channels.FileLock FileLock}. <p> * * <b>Configuration</b>:<p> * * To enable POSIX mandatory file lock tagging, set the system property * {@link #POSIX_MANDITORY_FILELOCK_PROPERTY} true. <p> * * <hr> * * <b><em>Windows</em><sup>tm</sup> File Locking Notes</b>:<p> * * There are two major differences between Unix and Windows locking.<p> * * First, <em>Windows</em><sup>tm</sup> supports a share reservation programming * interface. Share reservations apply to the entire file and are specified at * the time a file is created or opened. A share reservation consists of a pair * of modes. The first is the access mode, which is how the application will * access the file: read, write, or read/write. The second is the access * that the application will deny to other applications: none, read, write, * or read/write. When the application attempts to open a file, the operating * system checks to see if there are any other open requests on the file. If so, * it first compares the application's access mode with the deny mode of the * other openers. If there is a match, then the open is denied. If not, then * the operating system compares the application's deny mode with the access * mode of the other openers. Again, if there is a match, the open is denied.<p> * * Second, there is no advisory locking under <em>Windows</em>. Whole file * locking, byte range locking, and share reservation locking are all * mandatory. <p> * * As a side note, research indicates that very few <em>Windows</em> programs * actually rely on byte range mandatory locking. <p> * * <b>POSIX File Locking Notes</b>:<p> * * There are three commonly found locking functions under POSIX - flock, lockf, * and fcntl.<p> * * These functions, while managed by the kernel, are advisory locking mechanisms * by default. That is, the kernel does not actually stop programs from reading, * writing or deleting locked files. Instead, each program must check to see if * a lock is in place and act accordingly (be cooperative).<p> * * This might be problematic when some programs are cooperative and others are * not, especially if you do not have the ability to recompile the uncooperative * code, yet it must be allowed to run.<p> * * As POSIX has evolved, provisions have been made to allow locks to be enforced * at the kernel level with mandatory locking semantics. For historical reasons * <sup><a href="#note1">[1]</a></sup> and for practical reasons <sup> * <a href="#note2">[2]</a></sup>, POSIX mandatory locking is generally * implemented such that it must be configured on a file-by-file basis. When a * program attempts to lock a file with lockf or fcntl, the kernel will prevent * other programs from accessing the file if and only if the file has mandatory * locking set (note: processes which use flock never trigger a mandatory * lock).<p> * * In addition, to enable mandatory locking under Linux, the target filesystem * device must be mounted with the <tt>mand</tt> option, for example:<p> * * <pre> * # mount -omand /dev/hdb3 /mnt/data * * # mount | grep /mnt/data * /dev/hdb3 on /mnt/data type ext3 (rw,mand) *</pre> * * To automate this across reboots, <tt>mand</tt> must be added to the * appropriate <tt>/etc/fstab</tt> entry. <p> * * Although Linux, Solaris and HP/UX are known to support kernel-enforced * mandatory locking semantics, some POSIX systems may provide no support at all, * while others may have system-specific configuration prerequisites. Some may * even enforce manditory locking semantics by default under certain conditions * while others may silently ignore mandatory locking directives or consistently * raise exception conditions in response to such directives. <p> * * Regardless of any wider scoped prerequisites, restrictions and behavioural * variations, it is generally true under POSIX that only specifically tagged * files will exhibit mandatory locks. <p> * * And it is generally accepted that the way to designate a file to be governed * by mandatory locking semantics is to set its sgid (setgroupid) bit and unset * its group execute bit. This has become the commonly accepted practice * specifically because the combination is devoid of meaning in the regular * sense. <p> * * As a specific illustration, if mandatory locking is required on all * pre-existing files in a certain directory, then the corresponding * <tt>chmod</tt> invocation would be: <p> * * <pre> * $ chmod g+s,g-x /path/to/directory/* * </pre> * * <hr> * * <a name="note1"/>[1]</a> * The earliest versions of Unix had no way to lock files except to create * lock files. The idea is that two or more processes would more or less * simultaneously try to create a lock file in exclusive mode, via the * O_EXCL flag of the open( ) system call. The operating system would * return success to the process that won the race, and a "file exists" * error to losing processes. One problem with this scheme is that it * relies on the winning process to remove the lock file before it exits. * If the process is running buggy software, this might not happen. * Some applications mitigate this problem by recording the process ID of * the winner into the contents of the lock file. A process that finds that * it gets a "file exists" error can then read the lock file to see if the * owning process is still running. <p> * * Still, lock files can be clumsy. In the 1980s, Unix versions were * released with file locking support built into the operating system. * The System V branch of Unix offered file locking via the fcntl( ) system * call, whereas the BSD branch provided the flock( ) system call. In both * cases, when the process that creates the lock dies, the lock will be * automatically released. <p> * * In a perfect world all processes would use and honour a cooperative, or * "advisory" locking scheme. However, the world isn't perfect, and there's * a lot of poorly written code out there. <p> * * In trying to address this problem, the designers of System V UNIX came up * with a "mandatory" locking scheme, whereby the operating system kernel * would block attempts by a process to write to a file upon which another * process holds a "read" -or- "shared" lock, and block attempts both to * read and to write a file upon which a process holds a "write " -or- * "exclusive" lock. <p> * * The System V mandatory locking scheme was intended to have as little * impact as possible on existing user code. The scheme is based on marking * individual files as candidates for mandatory locking, and using the * existing fcntl()/lockf() interface for applying locks, just as if they * were normal, advisory locks. <p> * * <a name="note2"/>[2]</a> * Even with mandatory locks, conflicts can occur. If program A reads in a * file, program B locks, edits, and unlocks the file, and program A then * writes out what it originally read, this may still be less than * desirable. <p> * * As well, it is generally true that nothing can override a mandatory * lock, not even root-owned processes. In this situation, the best root * can do is kill the process that has the lock upon the file. <p> * * And this can be especially problematic if a file upon which a mandatory * lock exists is also available via NFS or some other remotely-accessible * filesystem, specifically because the entire fileserver process may be * forced to block until the lock is released. <p> * * Indeed, these effects of mandatory locking policy are commonly encountered in * the <em>Windows</em><sup>tm</sup> environment, where all locks are of the * mandatory style. <p> * * <hr> * * <b>Research Results</b>:<p> * * After some experimentation under JDK 1.5/6 and Linux (at least Fedora * Core 4), research results indicate that, after mounting the target file * system device using the described <tt>mand</tt> option and doing a * <tt>chmod g+s,g-x</tt> on the lock file before issuing a * <tt>FileChannel.tryLock(...)</tt>, it is still possible to delete the lock * file from another process while the resulting <tt>FileLock</tt> is held, * although mandatory locking does appear to be in effect for read/write * operations. <p> * * This result was actually the one anticipated, because deletion of open files * is generally possible under POSIX. In turn, this is because POSIX file * deletion simply removes the iNode entry from the file's parent directory, * while any processes with open file handles continue to have access to the * deleted file. Only when all file handles have been released does the space * occupied by the file become elligible for reuse.<p> * * In other words, under both <em>Windows</em><sup>tm</sup> and Linux (at lease * FC 4), it appears this class is a practically useless extension to the base. * Under Java for <em>Windows</em>, the act of holding a file handle open is * enough to produce a mandatory lock on the underlying file and also prevents * the file's deletion (i.e. the ultimately desired behavior occurs with or * without <tt>NIOLockFile</tt>), while under Java for Linux it appears * impossible to use NIO to produce a lock that prevents file deletion, yeilding * protection against inadvertent modification of the lock file practically * useless. <p> * * To put it another way, even after the much-heralded introduction of Java * NIO, without further resorting to platform-specific JNI alternatives, we * might as well still be back in the early 80's, because we cannot guarantee, * in a cross-platform manner, conditions better than offered by the earliest * known lock file approach, even on systems that do support mandatory file * locking semantics. Instead, we must simply still trust that all software is * well written and cooperative in nature. <p> * * @author boucherb@users * @version 1.8.0.3 * @since 1.7.2 */final class NIOLockFile extends LockFile { /** The largest lock region that can be specified with <tt>java.nio</tt>. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -