History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/nio/ch/FileLockTable.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/nio/ch/FileLockTable.java+273−0
@@ -0,0 +1,273 @@
1/*
2 * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.ch;
27
28import java.nio.channels.*;
29import java.util.*;
30import java.util.concurrent.ConcurrentHashMap;
31import java.lang.ref.*;
32import java.io.FileDescriptor;
33import java.io.IOException;
34
35abstract class FileLockTable {
36 protected FileLockTable() {
37 }
38
39 /**
40 * Creates and returns a file lock table for a channel that is connected to
41 * the a system-wide map of all file locks for the Java virtual machine.
42 */
43 public static FileLockTable newSharedFileLockTable(Channel channel,
44 FileDescriptor fd)
45 throws IOException
46 {
47 return new SharedFileLockTable(channel, fd);
48 }
49
50 /**
51 * Adds a file lock to the table.
52 *
53 * @throws OverlappingFileLockException if the file lock overlaps
54 * with an existing file lock in the table
55 */
56 public abstract void add(FileLock fl) throws OverlappingFileLockException;
57
58 /**
59 * Remove an existing file lock from the table.
60 */
61 public abstract void remove(FileLock fl);
62
63 /**
64 * Removes all file locks from the table.
65 *
66 * @return The list of file locks removed
67 */
68 public abstract List<FileLock> removeAll();
69
70 /**
71 * Replaces an existing file lock in the table.
72 */
73 public abstract void replace(FileLock fl1, FileLock fl2);
74}
75
76
77/**
78 * A file lock table that is over a system-wide map of all file locks.
79 */
80class SharedFileLockTable extends FileLockTable {
81
82 /**
83 * A weak reference to a FileLock.
84 * <p>
85 * SharedFileLockTable uses a list of file lock references to avoid keeping the
86 * FileLock (and FileChannel) alive.
87 */
88 private static class FileLockReference extends WeakReference<FileLock> {
89 private FileKey fileKey;
90
91 FileLockReference(FileLock referent,
92 ReferenceQueue<FileLock> queue,
93 FileKey key) {
94 super(referent, queue);
95 this.fileKey = key;
96 }
97
98 FileKey fileKey() {
99 return fileKey;
100 }
101 }
102
103 // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
104 // The map value is a list of file locks represented by FileLockReferences.
105 // All access to the list must be synchronized on the list.
106 private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
107 new ConcurrentHashMap<FileKey, List<FileLockReference>>();
108
109 // reference queue for cleared refs
110 private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
111
112 // The connection to which this table is connected
113 private final Channel channel;
114
115 // File key for the file that this channel is connected to
116 private final FileKey fileKey;
117
118 SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
119 this.channel = channel;
120 this.fileKey = FileKey.create(fd);
121 }
122
123 @Override
124 public void add(FileLock fl) throws OverlappingFileLockException {
125 List<FileLockReference> list = lockMap.get(fileKey);
126
127 for (;;) {
128
129 // The key isn't in the map so we try to create it atomically
130 if (list == null) {
131 list = new ArrayList<FileLockReference>(2);
132 List<FileLockReference> prev;
133 synchronized (list) {
134 prev = lockMap.putIfAbsent(fileKey, list);
135 if (prev == null) {
136 // we successfully created the key so we add the file lock
137 list.add(new FileLockReference(fl, queue, fileKey));
138 break;
139 }
140 }
141 // someone else got there first
142 list = prev;
143 }
144
145 // There is already a key. It is possible that some other thread
146 // is removing it so we re-fetch the value from the map. If it
147 // hasn't changed then we check the list for overlapping locks
148 // and add the new lock to the list.
149 synchronized (list) {
150 List<FileLockReference> current = lockMap.get(fileKey);
151 if (list == current) {
152 checkList(list, fl.position(), fl.size());
153 list.add(new FileLockReference(fl, queue, fileKey));
154 break;
155 }
156 list = current;
157 }
158
159 }
160
161 // process any stale entries pending in the reference queue
162 removeStaleEntries();
163 }
164
165 private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
166 assert Thread.holdsLock(list);
167 assert lockMap.get(fk) == list;
168 if (list.isEmpty()) {
169 lockMap.remove(fk);
170 }
171 }
172
173 @Override
174 public void remove(FileLock fl) {
175 assert fl != null;
176
177 // the lock must exist so the list of locks must be present
178 List<FileLockReference> list = lockMap.get(fileKey);
179 if (list == null) return;
180
181 synchronized (list) {
182 int index = 0;
183 while (index < list.size()) {
184 FileLockReference ref = list.get(index);
185 FileLock lock = ref.get();
186 if (lock == fl) {
187 assert (lock != null) && (lock.acquiredBy() == channel);
188 ref.clear();
189 list.remove(index);
190 break;
191 }
192 index++;
193 }
194 }
195 }
196
197 @Override
198 public List<FileLock> removeAll() {
199 List<FileLock> result = new ArrayList<FileLock>();
200 List<FileLockReference> list = lockMap.get(fileKey);
201 if (list != null) {
202 synchronized (list) {
203 int index = 0;
204 while (index < list.size()) {
205 FileLockReference ref = list.get(index);
206 FileLock lock = ref.get();
207
208 // remove locks obtained by this channel
209 if (lock != null && lock.acquiredBy() == channel) {
210 // remove the lock from the list
211 ref.clear();
212 list.remove(index);
213
214 // add to result
215 result.add(lock);
216 } else {
217 index++;
218 }
219 }
220
221 // once the lock list is empty we remove it from the map
222 removeKeyIfEmpty(fileKey, list);
223 }
224 }
225 return result;
226 }
227
228 @Override
229 public void replace(FileLock fromLock, FileLock toLock) {
230 // the lock must exist so there must be a list
231 List<FileLockReference> list = lockMap.get(fileKey);
232 assert list != null;
233
234 synchronized (list) {
235 for (int index=0; index<list.size(); index++) {
236 FileLockReference ref = list.get(index);
237 FileLock lock = ref.get();
238 if (lock == fromLock) {
239 ref.clear();
240 list.set(index, new FileLockReference(toLock, queue, fileKey));
241 break;
242 }
243 }
244 }
245 }
246
247 // Check for overlapping file locks
248 private void checkList(List<FileLockReference> list, long position, long size)
249 throws OverlappingFileLockException
250 {
251 assert Thread.holdsLock(list);
252 for (FileLockReference ref: list) {
253 FileLock fl = ref.get();
254 if (fl != null && fl.overlaps(position, size))
255 throw new OverlappingFileLockException();
256 }
257 }
258
259 // Process the reference queue
260 private void removeStaleEntries() {
261 FileLockReference ref;
262 while ((ref = (FileLockReference)queue.poll()) != null) {
263 FileKey fk = ref.fileKey();
264 List<FileLockReference> list = lockMap.get(fk);
265 if (list != null) {
266 synchronized (list) {
267 list.remove(ref);
268 removeKeyIfEmpty(fk, list);
269 }
270 }
271 }
272 }
273}