From 85a439fb39ffb14b077871e62a75bbe5a44e0f25 Mon Sep 17 00:00:00 2001 From: Michael Gamazaychikov Date: Fri, 9 Jan 2015 15:07:00 -0500 Subject: [PATCH] ASM #629 - GFE: when runProcedure terminates unexpectedly locks remain in gfelocktable. Change-Id: Ife5ecb2c5823d4d34c1b4af6dc53fa360074b7bb Former-commit-id: bae8d9ea3f52aad319194de8ef5d157d024188d6 [formerly bae8d9ea3f52aad319194de8ef5d157d024188d6 [formerly 38eabd6196df1576970019f2b0255d3f39a825a9]] Former-commit-id: e007fac30fa4a4ef42c2fb2a2c2980c3fe16da5b Former-commit-id: f034b8dab194aef5544de9ce666f7ce2ccc646fd --- .../res/spring/gfe-request.xml | 19 ++ .../com.raytheon.edex.plugin.gfe.properties | 3 + .../edex/plugin/gfe/db/dao/GFELockDao.java | 52 +++++ .../server/lock/ClearGfeOrphanedLocks.java | 210 ++++++++++++++++++ .../plugin/gfe/server/lock/LockManager.java | 17 ++ 5 files changed, 301 insertions(+) create mode 100644 edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/ClearGfeOrphanedLocks.java diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/res/spring/gfe-request.xml b/edexOsgi/com.raytheon.edex.plugin.gfe/res/spring/gfe-request.xml index 886ca478c0..82e2ce6c7a 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/res/spring/gfe-request.xml +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/res/spring/gfe-request.xml @@ -231,6 +231,9 @@ + + + @@ -426,6 +429,7 @@ + @@ -495,6 +499,21 @@ + + + + + + + + + + + java.lang.Throwable + + + + diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/resources/com.raytheon.edex.plugin.gfe.properties b/edexOsgi/com.raytheon.edex.plugin.gfe/resources/com.raytheon.edex.plugin.gfe.properties index 19315d2515..a229c239eb 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/resources/com.raytheon.edex.plugin.gfe.properties +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/resources/com.raytheon.edex.plugin.gfe.properties @@ -12,3 +12,6 @@ purge.svcbu.logs.cron=0+30+0+*+*+? # Interval at which the gfe products are purged purge.gfe.products.cron=0+45+0+*+*+? + +# Interval at which the gfe orphaned locks are cleared +clear.gfe.orphaned.locks.cron = 0+0/10+*+*+*+? \ No newline at end of file diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFELockDao.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFELockDao.java index 2b395a0042..03bf0a5808 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFELockDao.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/db/dao/GFELockDao.java @@ -53,6 +53,7 @@ import com.raytheon.uf.edex.database.dao.DaoConfig; * 04/19/13 #1949 rjpeter Normalized GFE Database. * 06/20/13 #2127 rjpeter Set session to read only. * 10/16/2014 3454 bphillip Upgrading to Hibernate 4 + * 01/07/15 629 mgamazaychikov Add getAllLocks method. * * * @author bphillip @@ -192,4 +193,55 @@ public class GFELockDao extends CoreDao { } } } + + @SuppressWarnings("unchecked") + public Map getAllLocks() throws DataAccessLayerException{ + Map lockMap = new HashMap(); + Session sess = null; + Transaction tx = null; + + try { + sess = getSession(); + sess.setDefaultReadOnly(true); + tx = sess.beginTransaction(); + + Query query = sess + .createQuery("FROM Lock"); + List locks = query.list(); + tx.commit(); + + // populate Lock table + for (Lock lock : locks) { + WsId wid = lock.getWsId(); + ParmID pid = lock.getParmId(); + LockTable lockTable = lockMap.get(pid); + if (lockTable == null) { + lockTable = new LockTable(pid, new ArrayList(), wid); + lockMap.put(pid, lockTable); + } + lockTable.addLock(lock); + } + return lockMap; + } catch (Exception e) { + if (tx != null) { + try { + tx.rollback(); + } catch (Exception e1) { + logger.error("Error occurred rolling back transaction", e1); + } + } + + throw new DataAccessLayerException( + "Unable to look up locks ", e); + } finally { + if (sess != null) { + try { + sess.close(); + } catch (Exception e) { + logger.error( + "Error occurred closing database session", e); + } + } + } + } } diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/ClearGfeOrphanedLocks.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/ClearGfeOrphanedLocks.java new file mode 100644 index 0000000000..af7d696396 --- /dev/null +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/ClearGfeOrphanedLocks.java @@ -0,0 +1,210 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package com.raytheon.edex.plugin.gfe.server.lock; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import com.raytheon.edex.plugin.gfe.server.IFPServer; +import com.raytheon.edex.plugin.gfe.server.lock.LockManager; +import com.raytheon.uf.common.dataplugin.gfe.server.lock.Lock; +import com.raytheon.uf.common.dataplugin.gfe.server.lock.LockTable; +import com.raytheon.uf.common.dataplugin.gfe.server.lock.LockTable.LockMode; +import com.raytheon.uf.common.dataplugin.gfe.server.request.LockRequest; +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.common.status.UFStatus.Priority; +import com.raytheon.uf.common.time.TimeRange; +import com.raytheon.uf.edex.core.EDEXUtil; +import com.raytheon.uf.edex.esb.camel.jms.IBrokerConnectionsProvider; + +/** + * GFE task to clear orphaned locks from the database table. Orphaned + * locks are locks whose session ID is not in the list of current Qpid + * sessions. + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 07, 2015  629    mgamazaychikov Initial creation
+ *
+ * 
+ * + * @author mgamazaychikov + * @version 1.0 + */ + +public class ClearGfeOrphanedLocks { + private static IBrokerConnectionsProvider provider; + private static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(ClearGfeOrphanedLocks.class); + public final String CAVE = "CAVE"; + + public static void setProvider(IBrokerConnectionsProvider provider) { + ClearGfeOrphanedLocks.provider = provider; + } + + private Set breakAllLocks(List lockTables, + LockManager lockMgr) { + Set inactives = new HashSet(); + for (LockTable lockTable : lockTables) { + for (Lock lock : lockTable.getLocks()) { + TimeRange tr = lock.getTimeRange(); + List lreq = new ArrayList(); + lreq.add(new LockRequest(lock.getParmId(), tr, + LockMode.BREAK_LOCK)); + lockMgr.requestLockChange(lreq, lock.getWsId()); + if (!inactives.contains(lock.getWsId().toPrettyString()) + && !inactives.contains(lock.getParmId().toString())) { + String message = " Breaking orphaned lock on " + + lock.getParmId().toString() + " owned by " + + lock.getWsId().toPrettyString() + "."; + inactives.add(message); + } + + } + } + return inactives; + } + + private Set breakLocks(Set clients, + List lockTables, LockManager lockMgr) { + Set inactives = new HashSet(); + for (LockTable lockTable : lockTables) { + for (Lock lock : lockTable.getLocks()) { + String lockedWsid = lock.getWsId().toString(); + for (String client : clients) { + if (!lockedWsid.equals(client)) { + // Inactive CAVE clients found - break its lock + List lreq = new ArrayList(); + lreq.add(new LockRequest(lock.getParmId(), lock + .getTimeRange(), LockMode.BREAK_LOCK)); + lockMgr.requestLockChange(lreq, lock.getWsId()); + if (!inactives + .contains(lock.getWsId().toPrettyString()) + && !inactives.contains(lock.getParmId() + .toString())) { + String message = " Breaking orphaned lock on " + + lock.getParmId().toString() + + " owned by " + + lock.getWsId().toPrettyString() + "."; + inactives.add(message); + } + + } + } + } + } + return inactives; + } + + @SuppressWarnings("unchecked") + public void clearLocksCron() throws Exception { + + Date executionTime = new Date(System.currentTimeMillis()); + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + String msg = "Started at " + executionTime; + statusHandler.info(msg); + } + + Set clients = new HashSet(provider.getConnections()); + Set inactives = new HashSet(); + + String siteId = EDEXUtil.getEdexSite(); + IFPServer ifpServer = IFPServer.getActiveServer(siteId); + if (ifpServer == null) { + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + String msg = "No active IFPServer for site " + siteId; + statusHandler.info(msg); + return; + } + } + LockManager lockMgr = ifpServer.getLockMgr(); + + List lockTables = (List) lockMgr.getAllLocks() + .getPayload(); + + /* + * There are no locks in the db. + */ + if (lockTables.size() == 0) { + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + String msg = "No locks found for site " + siteId; + statusHandler.info(msg); + return; + } + } + + /* + * Filter out non-CAVE clients. + */ + for (Iterator iterator = clients.iterator(); iterator.hasNext();) { + String client = iterator.next(); + if (!client.contains(CAVE)) { + iterator.remove(); + } + } + + /* + * If there are no active CAVE clients but the locks exist, they all + * must be orphaned -> break the locks. + */ + if (clients.isEmpty() && lockTables.size() > 0) { + inactives = breakAllLocks(lockTables, lockMgr); + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + StringBuilder sb = new StringBuilder(); + for (String in : inactives) { + sb.append(in); + } + statusHandler.info(sb.toString()); + return; + } + } + + /* + * There are active CAVE clients, find orphaned locks and break the + * locks. + */ + inactives = breakLocks(clients, lockTables, lockMgr); + if (inactives.isEmpty()) { + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + String msg = "No orphaned locks found for site " + siteId; + statusHandler.info(msg); + return; + } + } else { + if (statusHandler.isPriorityEnabled(Priority.INFO)) { + StringBuilder sb = new StringBuilder(); + for (String in : inactives) { + sb.append(in); + } + statusHandler.info(sb.toString()); + return; + } + } + } +} diff --git a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/LockManager.java b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/LockManager.java index ce19cd4fda..975af5630a 100644 --- a/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/LockManager.java +++ b/edexOsgi/com.raytheon.edex.plugin.gfe/src/com/raytheon/edex/plugin/gfe/server/lock/LockManager.java @@ -67,6 +67,7 @@ import com.raytheon.uf.edex.database.DataAccessLayerException; * fixed inefficiencies in querying/merging * 06/13/13 #2044 randerso Converted from singleton to instance per * site managed by IFPServer + * 01/07/15 629 mgamazaychikov Add getAllLocks method. * * * @author bphillip @@ -915,4 +916,20 @@ public class LockManager { return 0; } } + + public ServerResponse getAllLocks() { + ServerResponse> sr = new ServerResponse>(); + try { + List payLoad = null; + Map lockMap = dao.getAllLocks(); + payLoad = new ArrayList(lockMap.size()); + payLoad.addAll(lockMap.values()); + sr.setPayload(payLoad); + } catch (Exception e) { + sr.addMessage("Error getting lock tables for"); + sr.setPayload(new ArrayList(0)); + } + + return sr; + } }