/* * JBoss, Home of Professional Open Source * Copyright 2009 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.util.concurrent.locks.containers; import net.jcip.annotations.ThreadSafe; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; /** * A container for locks. Used with lock striping. * * @author Manik Surtani (<a href="mailto:manik@jboss.org">manik@jboss.org</a>) * @since 4.0 */ @ThreadSafe public abstract class AbstractStripedLockContainer<L extends Lock> extends AbstractLockContainer<L> { private int lockSegmentMask; private int lockSegmentShift; protected final int calculateNumberOfSegments(int concurrencyLevel) { int tempLockSegShift = 0; int numLocks = 1; while (numLocks < concurrencyLevel) { ++tempLockSegShift; numLocks <<= 1; } lockSegmentShift = 32 - tempLockSegShift; lockSegmentMask = numLocks - 1; return numLocks; } protected final int hashToIndex(Object object) { return (hash(object) >>> lockSegmentShift) & lockSegmentMask; } /** * Returns a hash code for non-null Object x. Uses the same hash code spreader as most other java.util hash tables, * except that this uses the string representation of the object passed in. * * @param object the object serving as a key * @return the hash code */ static final int hash(Object object) { int h = object.hashCode(); h += ~(h << 9); h ^= (h >>> 14); h += (h << 4); h ^= (h >>> 10); return h; } protected abstract void initLocks(int numLocks); @Override public L acquireExclusiveLock(Object lockOwner, Object key, long timeout, TimeUnit unit) throws InterruptedException { return acquire(lockOwner, key, timeout, unit, false); } @Override public L acquireShareLock(Object lockOwner, Object key, long timeout, TimeUnit unit) throws InterruptedException { return acquire(lockOwner, key, timeout, unit, true); } @Override public void releaseExclusiveLock(Object lockOwner, Object key) { final L lock = getExclusiveLock(key); safeExclusiveRelease(lock, lockOwner); } @Override public void releaseShareLock(Object lockOwner, Object key) { final L lock = getShareLock(key); safeExclusiveRelease(lock, lockOwner); } private L acquire(Object lockOwner, Object key, long timeout, TimeUnit unit, boolean share) throws InterruptedException { L lock = share ? getShareLock(key) : getExclusiveLock(key); boolean locked; try { locked = share ? tryShareLock(lock, timeout, unit, lockOwner) : tryExclusiveLock(lock, timeout, unit, lockOwner); } catch (InterruptedException ie) { if (share) { safeShareRelease(lock, lockOwner); } else { safeExclusiveRelease(lock, lockOwner); } throw ie; } catch (Throwable th) { if (share) { safeShareRelease(lock, lockOwner); } else { safeExclusiveRelease(lock, lockOwner); } locked = false; } return locked ? lock : null; } @Override public int getLockId(Object key) { return hashToIndex(key); } }