/* * Copyright (c) 2013 EMC Corporation * All Rights Reserved */ package com.emc.storageos.zkutils; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.emc.storageos.systemservices.impl.upgrade.CoordinatorClientExt; import com.emc.storageos.coordinator.client.model.Constants; /** * Handle upgrade lock to control upgrade and other process */ public class LockCmdHandler { private static final Logger log = LoggerFactory.getLogger(LockCmdHandler.class); private static final String ZKUTI_CONF = "/zkutils-conf.xml"; private static final String COORDINATOR_BEAN = "coordinatorclientext"; private static ApplicationContext ctx; private CoordinatorClientExt coordinatorClientExt; // syssvc id, like syssvc-1, syssvc-2 private String mysvcId; private String upgradeLockId; public LockCmdHandler() { // Suppress Sonar violation of Lazy initialization of static fields should be synchronized // This constructor used in Main, and only called in main thread, so it's safe to initialize ctx here ctx = new ClassPathXmlApplicationContext(ZKUTI_CONF); // NOSONAR("squid:S2444") coordinatorClientExt = (CoordinatorClientExt) ctx.getBean(COORDINATOR_BEAN); mysvcId = coordinatorClientExt.getMySvcId(); upgradeLockId = Constants.DISTRIBUTED_UPGRADE_LOCK; log.info("svcId of this node: {}", mysvcId); log.info("upgradeLockId: {}", upgradeLockId); } /** * Lock it before upgrade process starts. We grab two lock for different * nodes to make sure suspend the upgrading let other node to get the * upgrade lock and this node get the target lock */ public void aquireUpgradeLocks() { log.info("Start to lock the system to prevent upgrading..."); String leader = chooseOtherNodeSvcId(); // get upgrade lock boolean flag = coordinatorClientExt.getPersistentLock(leader, upgradeLockId); log.info("Get upgrade lock for {}, {}", leader, flag); if (flag) { // get target lock if (getTargetInfoLock()) { System.out.println("Succeed! Upgrade is Locking!"); } } else { log.error("Fail to get upgrade lock!"); throw new RuntimeException("Some node grabbed the lock already, " + "please try hold on the upgrade process method or release all first."); } } /** * Hold on the upgrade process */ public void aquireUpgradeLockByLoop() { System.out.println("Start busy loop to get the lock..."); boolean flag = false; String leader; while (flag != true) { // 1st, check someone hold the upgrade lock, means it is in upgrade process while ((leader = coordinatorClientExt.getUpgradeLockOwner(upgradeLockId)) != null) { // because the upgrade process will release the lock to let other nodes grab // 2nd, manually let leader get the lock again at the time it release the lock. while ((flag = coordinatorClientExt.getPersistentLock(leader, upgradeLockId)) != true) { leader = coordinatorClientExt.getUpgradeLockOwner(upgradeLockId); } System.out.println("Hold on Succeed!"); log.info("The {} get the lock, {}", leader, flag); break; } } } /** * Release all locks for upgrading continuously */ public void releaseAllLocks() { releaseTargetInfoLock(); if (releaseUpgradeLock()) { System.out.println("Release all lock succeed!"); } else { System.out.println("Relase Fail, Please see the log."); } } /** * Release upgrade lock * * @return true release successfully, otherwise false */ public boolean releaseUpgradeLock() { log.info("Strat releasing upgrade Lock ..."); boolean flag = false; String leader = coordinatorClientExt.getUpgradeLockOwner(upgradeLockId); if (leader != null) { log.info("Now upgrade lock belongs to: {}", leader); } try { flag = coordinatorClientExt.releasePersistentLock(upgradeLockId); } catch (Exception e) { log.error("Fail to release upgrade lock! {}", e); } log.info("Release upgrade lock: {}", flag); return flag; } /** * Get target info lock for this node * * @return true get successfully, otherwise false */ public boolean getTargetInfoLock() { log.info("Start getting target version lock"); boolean flag = false; flag = coordinatorClientExt.getTargetInfoLock(); log.info("Get target lock for {}, {}", mysvcId, flag); return flag; } /** * Release the non-persistent target version lock */ public void releaseTargetInfoLock() { log.info("Start releasing target version lock"); coordinatorClientExt.releaseTargetVersionLock(); log.info("Release the target version lock."); } /** * The method to identify and return the node which is currently holding the * persistent upgrade lock * * @return NodeHandle - for node which holds the lock, null - If no node * holds the lock */ public String getUpgradeLockOwner() { String leader = coordinatorClientExt.getUpgradeLockOwner(upgradeLockId); System.out.println(String.format("Lock belongs to leader: %s.", leader)); return leader; } /** * Get another node svc-id for getting upgrade lock * * @return another node svcid */ private String chooseOtherNodeSvcId() { List<String> nodes = coordinatorClientExt.getAllNodes(); for (String node : nodes) { if (!node.equals(mysvcId)) { log.info("Other node svc id is: {}", node); return node; } } log.info("No other node, return self"); return mysvcId; } }