151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/*
251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it
651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as
751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation.  Oracle designates this
851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided
951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code.
1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT
1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that
1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code).
1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version
1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation,
1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski *
2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any
2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions.
2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage sun.nio.ch;
2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.nio.channels.*;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.*;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.util.concurrent.ConcurrentHashMap;
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.lang.ref.*;
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.FileDescriptor;
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.io.IOException;
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiabstract class FileLockTable {
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    protected FileLockTable() {
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Creates and returns a file lock table for a channel that is connected to
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * the a system-wide map of all file locks for the Java virtual machine.
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public static FileLockTable newSharedFileLockTable(Channel channel,
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                                       FileDescriptor fd)
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws IOException
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return new SharedFileLockTable(channel, fd);
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Adds a file lock to the table.
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @throws OverlappingFileLockException if the file lock overlaps
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *         with an existing file lock in the table
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void add(FileLock fl) throws OverlappingFileLockException;
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Remove an existing file lock from the table.
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void remove(FileLock fl);
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Removes all file locks from the table.
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     *
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * @return  The list of file locks removed
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract List<FileLock> removeAll();
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * Replaces an existing file lock in the table.
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public abstract void replace(FileLock fl1, FileLock fl2);
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/**
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * A file lock table that is over a system-wide map of all file locks.
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass SharedFileLockTable extends FileLockTable {
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /**
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * A weak reference to a FileLock.
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * <p>
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * SharedFileLockTable uses a list of file lock references to avoid keeping the
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     * FileLock (and FileChannel) alive.
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski     */
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static class FileLockReference extends WeakReference<FileLock> {
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        private FileKey fileKey;
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        FileLockReference(FileLock referent,
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          ReferenceQueue<FileLock> queue,
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                          FileKey key) {
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            super(referent, queue);
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            this.fileKey = key;
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        FileKey fileKey() {
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return fileKey;
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // The map value is a list of file locks represented by FileLockReferences.
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // All access to the list must be synchronized on the list.
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        new ConcurrentHashMap<FileKey, List<FileLockReference>>();
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // reference queue for cleared refs
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // The connection to which this table is connected
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final Channel channel;
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // File key for the file that this channel is connected to
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final FileKey fileKey;
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.channel = channel;
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        this.fileKey = FileKey.create(fd);
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Override
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void add(FileLock fl) throws OverlappingFileLockException {
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<FileLockReference> list = lockMap.get(fileKey);
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (;;) {
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // The key isn't in the map so we try to create it atomically
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (list == null) {
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                list = new ArrayList<FileLockReference>(2);
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                List<FileLockReference> prev;
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                synchronized (list) {
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    prev = lockMap.putIfAbsent(fileKey, list);
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (prev == null) {
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // we successfully created the key so we add the file lock
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        list.add(new FileLockReference(fl, queue, fileKey));
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        break;
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // someone else got there first
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                list = prev;
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // There is already a key. It is possible that some other thread
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // is removing it so we re-fetch the value from the map. If it
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // hasn't changed then we check the list for overlapping locks
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // and add the new lock to the list.
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            synchronized (list) {
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                List<FileLockReference> current = lockMap.get(fileKey);
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (list == current) {
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    checkList(list, fl.position(), fl.size());
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    list.add(new FileLockReference(fl, queue, fileKey));
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                list = current;
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // process any stale entries pending in the reference queue
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        removeStaleEntries();
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert Thread.holdsLock(list);
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert lockMap.get(fk) == list;
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (list.isEmpty()) {
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            lockMap.remove(fk);
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Override
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void remove(FileLock fl) {
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert fl != null;
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // the lock must exist so the list of locks must be present
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<FileLockReference> list = lockMap.get(fileKey);
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (list == null) return;
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (list) {
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            int index = 0;
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            while (index < list.size()) {
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                FileLockReference ref = list.get(index);
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                FileLock lock = ref.get();
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (lock == fl) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    assert (lock != null) && (lock.acquiredBy() == channel);
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ref.clear();
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    list.remove(index);
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                index++;
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Override
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public List<FileLock> removeAll() {
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<FileLock> result = new ArrayList<FileLock>();
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<FileLockReference> list = lockMap.get(fileKey);
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (list != null) {
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            synchronized (list) {
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                int index = 0;
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                while (index < list.size()) {
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    FileLockReference ref = list.get(index);
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    FileLock lock = ref.get();
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // remove locks obtained by this channel
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (lock != null && lock.acquiredBy() == channel) {
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // remove the lock from the list
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        ref.clear();
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        list.remove(index);
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // add to result
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        result.add(lock);
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    } else {
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        index++;
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                // once the lock list is empty we remove it from the map
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                removeKeyIfEmpty(fileKey, list);
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return result;
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    @Override
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public void replace(FileLock fromLock, FileLock toLock) {
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // the lock must exist so there must be a list
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        List<FileLockReference> list = lockMap.get(fileKey);
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert list != null;
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        synchronized (list) {
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            for (int index=0; index<list.size(); index++) {
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                FileLockReference ref = list.get(index);
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                FileLock lock = ref.get();
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (lock == fromLock) {
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    ref.clear();
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    list.set(index, new FileLockReference(toLock, queue, fileKey));
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    break;
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Check for overlapping file locks
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void checkList(List<FileLockReference> list, long position, long size)
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws OverlappingFileLockException
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    {
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        assert Thread.holdsLock(list);
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (FileLockReference ref: list) {
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            FileLock fl = ref.get();
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (fl != null && fl.overlaps(position, size))
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                throw new OverlappingFileLockException();
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Process the reference queue
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private void removeStaleEntries() {
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        FileLockReference ref;
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while ((ref = (FileLockReference)queue.poll()) != null) {
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            FileKey fk = ref.fileKey();
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            List<FileLockReference> list = lockMap.get(fk);
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (list != null) {
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                synchronized (list) {
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    list.remove(ref);
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    removeKeyIfEmpty(fk, list);
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
274