1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.nio.channels;
19 
20 import java.io.IOException;
21 
22 /**
23  * A {@code FileLock} represents a locked region of a file.
24  * <p>
25  * Locks have certain properties that enable collaborating processes to avoid
26  * the lost update problem or reading inconsistent data. Logically, a file lock
27  * can be <em>exclusive</em> or <em>shared</em>. Multiple processes can hold
28  * shared locks on the same region of a file, but only a single process can hold
29  * an exclusive lock on a given region of a file and no other process can
30  * simultaneously hold a shared lock overlapping the exclusive lock. An
31  * application can determine whether a {@code FileLock} is shared or exclusive
32  * via the {@code isShared()} method.
33  * <p>
34  * Locks held by a particular process cannot overlap one another. Applications
35  * can determine whether a proposed lock will overlap by using the {@code
36  * overlaps(long, long)}) method. Locks held in other processes may overlap
37  * locks held in this process. Locks are shared amongst all threads in the
38  * acquiring process, and are therefore unsuitable for intra-process
39  * synchronization.
40  * <p>
41  * Once a lock is acquired, it is immutable in all its state except {@code
42  * isValid()}. The lock will initially be valid, but may be rendered invalid by
43  * explicit removal of the lock, using {@code release()}, or implicitly by
44  * closing the channel or exiting the process (terminating the VM).
45  * <h3>Platform dependencies</h3>
46  * <p>
47  * Locks are intended to be true platform operating system file locks, and
48  * therefore locks held by the VM will be visible to other
49  * operating system processes.
50  * <p>
51  * The characteristics of the underlying operating system locks will show
52  * through in the Java implementation. For example, some platforms' locks are
53  * 'mandatory' -- meaning the operating system enforces the locks on processes
54  * that attempt to access locked regions of files; whereas other platforms'
55  * locks are only 'advisory' -- meaning that processes are required to
56  * collaborate to ensure locks are acquired and there is a potential for
57  * processes to not play well. To be on the safe side, it is best to assume that
58  * the platform is adopting advisory locks and always acquire shared locks when
59  * reading a region of a file.
60  * <p>
61  * On some platforms, the presence of a lock will prevent the file from being
62  * memory-mapped. On some platforms, closing a channel on a given file handle
63  * will release all the locks held on that file -- even if there are other
64  * channels open on the same file; their locks will also be released. The safe
65  * option here is to ensure that you only acquire locks on a single channel for
66  * a particular file and that becomes the synchronization point.
67  * <p>
68  * Further care should be exercised when locking files maintained on network
69  * file systems, since they often have further limitations.
70  */
71 public abstract class FileLock implements AutoCloseable {
72 
73     // The underlying file channel.
74     private final FileChannel channel;
75 
76     // The lock starting position.
77     private final long position;
78 
79     // The lock length in bytes
80     private final long size;
81 
82     // If true then shared, if false then exclusive
83     private final boolean shared;
84 
85     /**
86      * Constructs a new file lock instance for a given channel. The constructor
87      * enforces the starting position, length and sharing mode of the lock.
88      *
89      * @param channel
90      *            the underlying file channel that holds the lock.
91      * @param position
92      *            the starting point for the lock.
93      * @param size
94      *            the length of the lock in number of bytes.
95      * @param shared
96      *            the lock's sharing mode of lock; {@code true} is shared,
97      *            {@code false} is exclusive.
98      */
FileLock(FileChannel channel, long position, long size, boolean shared)99     protected FileLock(FileChannel channel, long position, long size, boolean shared) {
100         if (position < 0 || size < 0 || position + size < 0) {
101             throw new IllegalArgumentException("position=" + position + " size=" + size);
102         }
103         this.channel = channel;
104         this.position = position;
105         this.size = size;
106         this.shared = shared;
107     }
108 
109     /**
110      * Returns the lock's {@link FileChannel}.
111      */
channel()112     public final FileChannel channel() {
113         return channel;
114     }
115 
116     /**
117      * Returns the lock's starting position in the file.
118      *
119      * @return the lock position.
120      */
position()121     public final long position() {
122         return position;
123     }
124 
125     /**
126      * Returns the length of the file lock in bytes.
127      *
128      * @return the size of the file lock in bytes.
129      */
size()130     public final long size() {
131         return size;
132     }
133 
134     /**
135      * Indicates if the file lock is shared with other processes or if it is
136      * exclusive.
137      *
138      * @return {@code true} if the lock is a shared lock, {@code false} if it is
139      *         exclusive.
140      */
isShared()141     public final boolean isShared() {
142         return shared;
143     }
144 
145     /**
146      * Indicates if the receiver's lock region overlaps the region described
147      * in the parameter list.
148      *
149      * @param start
150      *            the starting position for the comparative lock.
151      * @param length
152      *            the length of the comparative lock.
153      * @return {@code true} if there is an overlap, {@code false} otherwise.
154      */
overlaps(long start, long length)155     public final boolean overlaps(long start, long length) {
156         final long end = position + size - 1;
157         final long newEnd = start + length - 1;
158         if (end < start || position > newEnd) {
159             return false;
160         }
161         return true;
162     }
163 
164     /**
165      * Indicates whether this lock is a valid file lock. The lock is
166      * valid unless the underlying channel has been closed or it has been
167      * explicitly released.
168      *
169      * @return {@code true} if the lock is valid, {@code false} otherwise.
170      */
isValid()171     public abstract boolean isValid();
172 
173     /**
174      * Releases this particular lock on the file. If the lock is invalid then
175      * this method has no effect. Once released, the lock becomes invalid.
176      *
177      * @throws ClosedChannelException
178      *             if the channel is already closed when an attempt to release
179      *             the lock is made.
180      * @throws IOException
181      *             if another I/O error occurs.
182      */
release()183     public abstract void release() throws IOException;
184 
185     /**
186      * Calls {@link #release} for {@code AutoCloseable}.
187      *
188      * @since 1.7
189      */
close()190     public final void close() throws IOException {
191         release();
192     }
193 
194     /**
195      * Returns a string that shows the details of the lock suitable for debugging.
196      */
197     @Override
toString()198     public final String toString() {
199         return "FileLock[position=" + position + ", size=" + size + ", shared=" + shared + "]";
200     }
201 }
202