/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.networkcontroller.impl; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.coordinator.client.service.CoordinatorClient; import com.emc.storageos.networkcontroller.exceptions.NetworkDeviceControllerException; import org.apache.curator.framework.recipes.locks.InterProcessLock; /** * NetworkFabricLocker -- The idea of locking a SAN fabric is to avoid simultaneous * zoning operations on the same SAN fabric (from different threads) on the Brocade BNA/CMCNE. * If multiple concurrent zoning operations are attempted various session locking / commit * failures have been observed on the Brocade. * This will also avoid simultaneous operations on the same VSAN on the Ciscos. * * Failure to acquire session locks or commit sessions can still occur, however now will * be caused by zoning operations initiated externally to this ViPR instance (either in * a different ViPR instance or directly on the networking equipment.) * * Locking will also slightly help throughput... previously when we could not obtain a * session lock we retried periodically (once per minute). * Now as soon as the fabric lock is released, * another thread is awakened to receive the fabric lock and can commence right away. * * @author watson */ public class NetworkFabricLocker { private static final Logger _log = LoggerFactory.getLogger(NetworkFabricLocker.class); private static String getLockName(String fabricId) { return "san-fabrics/" + fabricId; } /** * Creates a new or retrieves an existing fabric lock from the coordinator. * * @param fabricId - String * @param coordinator * @return InterProcessLock */ private static InterProcessLock getFabricLock(String fabricId, CoordinatorClient coordinator) { String lockName = getLockName(fabricId); try { InterProcessLock lock = coordinator.getLock(lockName); return lock; } catch (Exception ex) { _log.error("Could not get lock: " + lockName); throw NetworkDeviceControllerException.exceptions.couldNotGetFabricLock(fabricId, ex); } } /** * Acquires a fabric exclusive lock based on the fabricId. * * @param fabricId - String * @param coordinator * @return InterProcessLock (must be passed to unlock) */ public static InterProcessLock lockFabric(String fabricId, CoordinatorClient coordinator) { boolean acquired = false; InterProcessLock lock = getFabricLock(fabricId, coordinator); try { acquired = lock.acquire(60, TimeUnit.MINUTES); } catch (Exception ex) { _log.error("Exception locking fabric: " + fabricId); throw NetworkDeviceControllerException.exceptions.exceptionAcquiringFabricLock(fabricId, ex); } if (acquired == false) { _log.error("Unable to lock fabric lock: " + fabricId); throw NetworkDeviceControllerException.exceptions.couldNotAcquireFabricLock(fabricId); } return lock; } /** * Releases a fabric exclusive lock based on the fabricId. * * @param fabricId * @param lock */ public static void unlockFabric(String fabricId, InterProcessLock lock) { try { if (lock != null) { lock.release(); } } catch (Exception ex) { _log.error("Exception unlocking fabric: " + fabricId); throw NetworkDeviceControllerException.exceptions.exceptionReleasingFabricLock(fabricId, ex); } } }