/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.gwc.layer; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.geoserver.platform.ServiceException; /** * A wrapper around a ReadWriteLock that will perform all locking operations under a timeout to prevent deadlocks. * * @author Andrea Aime - GeoSolutions */ class TimeoutReadWriteLock { ReadWriteLock lock = new ReentrantReadWriteLock(); int timeoutMs; String name; /** * Builds the {@link ReadWriteLock} wrapper with a given timeout, in milliseconds * @param timeoutMs */ public TimeoutReadWriteLock(int timeoutMs, String name) { this.timeoutMs = timeoutMs; this.name = name; } /** * Acquires a read lock with the configured timeout, will throw a {@link ServiceException} if the lock is not acquired */ public void acquireReadLock() { boolean acquired = false; try { acquired = lock.readLock().tryLock(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new ServiceException("Failed to acquire read lock on '" + name + "' due to interruption", e); } if (!acquired) { throw new ServiceException( "Failed to acquire read lock on '" + name + "' in less than " + timeoutMs + " ms"); } } /** * Releases a previously acquired read lock */ public void releaseReadLock() { lock.readLock().unlock(); } /** * Acquires a write lock with the configured timeout, will throw a {@link ServiceException} if the lock is not acquired */ public void acquireWriteLock() { boolean acquired = false; try { acquired = lock.writeLock().tryLock(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { throw new ServiceException("Failed to acquire write lock on '" + name + "' due to interruption", e); } if (!acquired) { throw new ServiceException( "Failed to acquire write lock on '" + name + "' in less than " + timeoutMs + " ms"); } } /** * Releases a previously acquired write lock */ public void releaseWriteLock() { lock.writeLock().unlock(); } /** * Downgrades a write lock to a read lock. The write lock gets released, the caller must still release the read lock after this is called */ public void downgradeToReadLock() { // Downgrade by acquiring read lock before releasing write lock lock.readLock().lock(); // Unlock write, still hold read lock.writeLock().unlock(); } }