< prev index next >

src/java.base/share/classes/sun/nio/ch/FileLockTable.java

Print this page


   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


  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  */
  80 class 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);


 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);


 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 }
   1 /*
   2  * Copyright (c) 2005, 2018, 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


  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  */
  80 class 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 final FileKey fileKey;
  90         final long position;
  91         final long size;
  92         private volatile boolean invalid;
  93 
  94         FileLockReference(FileLock referent,
  95                           ReferenceQueue<FileLock> queue,
  96                           FileKey key) {
  97             super(referent, queue);
  98             this.fileKey = key;
  99             this.position = referent.position();
 100             this.size = referent.size();
 101         }
 102 
 103         FileKey fileKey() {
 104             return fileKey;
 105         }
 106 
 107         void invalidate() {
 108             invalid = true;
 109         }
 110 
 111         boolean isValid() {
 112             return !invalid;
 113         }
 114 
 115         boolean overlaps(long position, long size) {
 116             if (position + size <= this.position)
 117                 return false;               // That is below this
 118             if (this.position + this.size <= position)
 119                 return false;               // This is below that
 120             return true;
 121         }
 122     }
 123 
 124     // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
 125     // The map value is a list of file locks represented by FileLockReferences.
 126     // All access to the list must be synchronized on the list.
 127     private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
 128         new ConcurrentHashMap<FileKey, List<FileLockReference>>();
 129 
 130     // reference queue for cleared refs
 131     private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
 132 
 133     // The connection to which this table is connected
 134     private final Channel channel;
 135 
 136     // File key for the file that this channel is connected to
 137     private final FileKey fileKey;
 138 
 139     SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
 140         this.channel = channel;
 141         this.fileKey = FileKey.create(fd);


 190             lockMap.remove(fk);
 191         }
 192     }
 193 
 194     @Override
 195     public void remove(FileLock fl) {
 196         assert fl != null;
 197 
 198         // the lock must exist so the list of locks must be present
 199         List<FileLockReference> list = lockMap.get(fileKey);
 200         if (list == null) return;
 201 
 202         synchronized (list) {
 203             int index = 0;
 204             while (index < list.size()) {
 205                 FileLockReference ref = list.get(index);
 206                 FileLock lock = ref.get();
 207                 if (lock == fl) {
 208                     assert (lock != null) && (lock.acquiredBy() == channel);
 209                     ref.clear();
 210                     ref.invalidate();
 211                     list.remove(index);
 212                     break;
 213                 }
 214                 index++;
 215             }
 216         }
 217     }
 218 
 219     @Override
 220     public List<FileLock> removeAll() {
 221         List<FileLock> result = new ArrayList<FileLock>();
 222         List<FileLockReference> list = lockMap.get(fileKey);
 223         if (list != null) {
 224             synchronized (list) {
 225                 int index = 0;
 226                 while (index < list.size()) {
 227                     FileLockReference ref = list.get(index);
 228                     FileLock lock = ref.get();
 229 
 230                     // remove locks obtained by this channel
 231                     if (lock != null && lock.acquiredBy() == channel) {
 232                         // remove the lock from the list
 233                         ref.clear();
 234                         ref.invalidate();
 235                         list.remove(index);
 236 
 237                         // add to result
 238                         result.add(lock);
 239                     } else {
 240                         index++;
 241                     }
 242                 }
 243 
 244                 // once the lock list is empty we remove it from the map
 245                 removeKeyIfEmpty(fileKey, list);
 246             }
 247         }
 248         return result;
 249     }
 250 
 251     @Override
 252     public void replace(FileLock fromLock, FileLock toLock) {
 253         // the lock must exist so there must be a list
 254         List<FileLockReference> list = lockMap.get(fileKey);


 257         synchronized (list) {
 258             for (int index=0; index<list.size(); index++) {
 259                 FileLockReference ref = list.get(index);
 260                 FileLock lock = ref.get();
 261                 if (lock == fromLock) {
 262                     ref.clear();
 263                     list.set(index, new FileLockReference(toLock, queue, fileKey));
 264                     break;
 265                 }
 266             }
 267         }
 268     }
 269 
 270     // Check for overlapping file locks
 271     private void checkList(List<FileLockReference> list, long position, long size)
 272         throws OverlappingFileLockException
 273     {
 274         assert Thread.holdsLock(list);
 275         for (FileLockReference ref: list) {
 276             FileLock fl = ref.get();
 277             if ((fl != null || ref.isValid()) && ref.overlaps(position, size))
 278                 throw new OverlappingFileLockException();
 279         }
 280     }
 281 
 282     // Process the reference queue
 283     private void removeStaleEntries() {
 284         FileLockReference ref;
 285         while ((ref = (FileLockReference)queue.poll()) != null) {
 286             FileKey fk = ref.fileKey();
 287             List<FileLockReference> list = lockMap.get(fk);
 288             if (list != null) {
 289                 synchronized (list) {
 290                     if (!ref.isValid()) {
 291                         list.remove(ref);
 292                     }
 293                     removeKeyIfEmpty(fk, list);
 294                 }
 295             }
 296         }
 297     }
 298 }
< prev index next >