/* * Copyright (c) 2016 EMC Corporation * All Rights Reserved */ package com.emc.storageos.storagedriver.impl; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import com.emc.storageos.storagedriver.LockManager; /** * In memory implementation of LockManager. * This implementation provides re-entrant locks. * * Can be used for driver verification/testing. */ public class InMemoryLockManagerImpl implements LockManager { // lock name to holding thread name map private Map<String, String> locks = new HashMap<>(); // lock name to map of thread names waiting for this lock. // map of threads: key --- thread name, time to stop waiting private Map<String, Map<String, Long>> lockNameToThreads = new HashMap<>(); @Override public synchronized boolean acquireLock(String lockName, long timeout, TimeUnit unit) { long timeoutMilliSeconds = TimeUnit.MILLISECONDS.convert(timeout, unit); String threadName = Thread.currentThread().getName(); Map<String, Long> threadToTime = lockNameToThreads.get(lockName); if (threadToTime == null) { threadToTime = new HashMap<>(); lockNameToThreads.put(lockName, threadToTime); } Long waitUntil = System.currentTimeMillis() + timeoutMilliSeconds; while (!(locks.get(lockName) == null || locks.get(lockName).equals(threadName))) { // locked by other thread Long timeRemaining; if (threadToTime.get(threadName) != null) { // thread is already waiting. adjust remaining wait time. timeRemaining = threadToTime.get(threadName)-System.currentTimeMillis(); } else { // first attempt to lock by the thread threadToTime.put(threadName, waitUntil); timeRemaining = timeoutMilliSeconds; } if (timeRemaining <= 0) { // timeout elapsed threadToTime.remove(threadName); return false; } try { wait(timeRemaining); } catch (InterruptedException e) { // do nothing } } // lock is available threadToTime.remove(threadName); locks.put(lockName, threadName); return true; } @Override public synchronized boolean releaseLock(String lockName) { locks.remove(lockName); notifyAll(); return true; } }