java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataAction.java | 1 java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataEvent.java | 13 + java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java | 27 --- java/code/src/com/redhat/rhn/manager/errata/AsyncErrataCloneCounter.java | 74 ++++++++++ java/code/src/com/redhat/rhn/manager/errata/ErrataManager.java | 12 + java/spacewalk-java.spec | 5 rel-eng/packages/spacewalk-java | 2 7 files changed, 110 insertions(+), 24 deletions(-)
New commits: commit 2de3ceb59ad5116cf6bab7c09724cb3552406c36 Author: Stephen Herr sherr@redhat.com Date: Tue Jun 26 14:46:23 2012 -0400
Automatic commit of package [spacewalk-java] release [1.8.98-1].
diff --git a/java/spacewalk-java.spec b/java/spacewalk-java.spec index dd8204c..2b65ffe 100644 --- a/java/spacewalk-java.spec +++ b/java/spacewalk-java.spec @@ -23,7 +23,7 @@ Name: spacewalk-java Summary: Spacewalk Java site packages Group: Applications/Internet License: GPLv2 -Version: 1.8.97 +Version: 1.8.98 Release: 1%{?dist} URL: https://fedorahosted.org/spacewalk Source0: https://fedorahosted.org/releases/s/p/spacewalk/%%7Bname%7D-%%7Bversion%7D.t... @@ -615,6 +615,9 @@ fi %{jardir}/postgresql-jdbc.jar
%changelog +* Tue Jun 26 2012 Stephen Herr sherr@redhat.com 1.8.98-1 +- 829485 - resolveing potential deadlock during asynchronous errata clone + * Tue Jun 26 2012 Jan Pazdziora 1.8.97-1 - Each dataset must have a different name. - Add CSV downloader for scap search page. diff --git a/rel-eng/packages/spacewalk-java b/rel-eng/packages/spacewalk-java index a6ddb83..5b9f9ed 100644 --- a/rel-eng/packages/spacewalk-java +++ b/rel-eng/packages/spacewalk-java @@ -1 +1 @@ -1.8.97-1 java/ +1.8.98-1 java/
commit 7713d370ccb509980056ecd18a5846960f964458 Author: Stephen Herr sherr@redhat.com Date: Tue Jun 26 14:46:08 2012 -0400
829485 - resolveing potential deadlock during asynchronous errata clone
diff --git a/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataAction.java b/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataAction.java index 74a64a5..d2db2ea 100644 --- a/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataAction.java +++ b/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataAction.java @@ -43,5 +43,6 @@ extends AbstractDatabaseAction { errata.add(ErrataFactory.lookupById(eid)); ErrataManager.cloneErrataApi(msg.getChan(), errata, msg.getUser(), msg.isInheritPackages()); + msg.deregister(); } } diff --git a/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataEvent.java b/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataEvent.java index 458d126..7b8f173 100644 --- a/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataEvent.java +++ b/java/code/src/com/redhat/rhn/frontend/events/NewCloneErrataEvent.java @@ -20,6 +20,7 @@ import com.redhat.rhn.domain.channel.Channel; import com.redhat.rhn.domain.channel.ChannelFactory; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.domain.user.UserFactory; +import com.redhat.rhn.manager.errata.AsyncErrataCloneCounter;
import org.hibernate.Transaction;
@@ -128,5 +129,17 @@ public class NewCloneErrataEvent implements EventDatabaseMessage { return UserFactory.lookupById(userId); }
+ /** + * Register the async clone event with the counter + */ + public void register() { + AsyncErrataCloneCounter.getInstance().addAsyncErrataCloneJob(chanId); + }
+ /** + * De-regiser the async clone event from the counter + */ + public void deregister() { + AsyncErrataCloneCounter.getInstance().removeAsyncErrataCloneJob(chanId); + } } diff --git a/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java b/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java index d557ee7..49aca00 100644 --- a/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java +++ b/java/code/src/com/redhat/rhn/frontend/xmlrpc/errata/ErrataHandler.java @@ -865,11 +865,6 @@ public class ErrataHandler extends BaseHandler { * * @xmlrpc.doc Clone a list of errata into the specified channel. * - * Warning: Issuing a synchronous clone request for a channel that has asynchronous - * errata cloning jobs pending can result in a database deadlock! Adding more - * asynchronous jobs is safe. If deadlock occurs one must re-schedule both the - * synchronous and asynchronous jobs to ensure all errata are cloned. - * * @xmlrpc.param #session_key() * @xmlrpc.param #param("string", "channel_label") * @xmlrpc.param @@ -896,11 +891,6 @@ public class ErrataHandler extends BaseHandler { * * @xmlrpc.doc Asynchronously clone a list of errata into the specified channel. * - * Warning: Issuing a synchronous clone request for a channel that has asynchronous - * errata cloning jobs pending can result in a database deadlock! Adding more - * asynchronous jobs is safe. If deadlock occurs one must re-schedule both the - * synchronous and asynchronous jobs to ensure all errata are cloned. - * * @xmlrpc.param #session_key() * @xmlrpc.param #param("string", "channel_label") * @xmlrpc.param @@ -968,6 +958,13 @@ public class ErrataHandler extends BaseHandler { inheritPackages); return new ArrayList<Errata>().toArray(); } + else if (ErrataManager.channelHasPendingAsyncCloneJobs(channel)) { + throw new InvalidChannelException( + "Channel " + + channel.getLabel() + + " has pending asynchronous errata clone jobs. You must wait" + + "until asychronous errata clone jobs are done."); + } return ErrataManager.cloneErrataApi(channel, errataToClone, loggedInUser, inheritPackages); } @@ -987,11 +984,6 @@ public class ErrataHandler extends BaseHandler { * @xmlrpc.doc Clones a list of errata into a specified cloned channel * according the original erratas. * - * Warning: Issuing a synchronous cloneAsOriginal request for a channel that has - * asynchronous errata cloning jobs pending can result in a database deadlock! Adding - * more asynchronous jobs is safe. If deadlock occurs one must re-schedule both the - * synchronous and asynchronous jobs to ensure all errata are cloned. - * * @xmlrpc.param #session_key() * @xmlrpc.param #param("string", "channel_label") * @xmlrpc.param @@ -1020,11 +1012,6 @@ public class ErrataHandler extends BaseHandler { * @xmlrpc.doc Asynchronously clones a list of errata into a specified cloned channel * according the original erratas * - * Warning: Issuing a synchronous cloneAsOriginal request for a channel that has - * asynchronous errata cloning jobs pending can result in a database deadlock! Adding - * more asynchronous jobs is safe. If deadlock occurs one must re-schedule both the - * synchronous and asynchronous jobs to ensure all errata are cloned. - * * @xmlrpc.param #session_key() * @xmlrpc.param #param("string", "channel_label") * @xmlrpc.param diff --git a/java/code/src/com/redhat/rhn/manager/errata/AsyncErrataCloneCounter.java b/java/code/src/com/redhat/rhn/manager/errata/AsyncErrataCloneCounter.java new file mode 100644 index 0000000..ed3d528 --- /dev/null +++ b/java/code/src/com/redhat/rhn/manager/errata/AsyncErrataCloneCounter.java @@ -0,0 +1,74 @@ +package com.redhat.rhn.manager.errata; + +import java.util.Hashtable; + +/** + * If someone attempts to schedule a synchronous errata clone into a + * channel that has asynchronous errata clones taking place in the + * background, a database deadlock will occur. There is no way to + * avoid the deadlock, so instead we'll keep track of how many + * pending jobs we have here. The jobs themselves are not persistent, + * residing in tomcat memory only, so the counter should not be + * persistent. That is why I implemented the counter as a singeton + * class instead of a database table or some other such implementation. + * + * @author Stephen Herr sherr@redhat.com + * + */ +public class AsyncErrataCloneCounter { + // hashtable is syncronized, so is threadsafe + private final Hashtable<Long, Integer> count; + private static AsyncErrataCloneCounter instance = new AsyncErrataCloneCounter(); + + private AsyncErrataCloneCounter() { + count = new Hashtable<Long, Integer>(); + } + + /** + * Get the one and only instance of AsyncErrataCloneCounter + * @return the singleton instance + */ + public static AsyncErrataCloneCounter getInstance() { + return instance; + } + + /** + * Check if a channel has pending asyncrhonous errata clone jobs + * @param cid channel id + * @return True if there are pending jobs for a channel, false otherwise + */ + public boolean channelHasPendingJobs(Long cid) { + Integer n = count.get(cid); + if (n == null || n == 0) { + return false; + } + return true; + } + + /** + * Call this with the channel id when scheduling a new asyncronous + * errata clone job + * @param cid channel id + */ + public void addAsyncErrataCloneJob(Long cid) { + Integer n = count.get(cid); + if (n != null) { + count.put(cid, n + 1); + } + else { + count.put(cid, 1); + } + } + + /** + * Call this with channel id when completeing an asynchronous + * errata clone job + * @param cid channel id + */ + public void removeAsyncErrataCloneJob(Long cid) { + Integer n = count.get(cid); + if (n != null && n > 0) { + count.put(cid, n - 1); + } + } +} diff --git a/java/code/src/com/redhat/rhn/manager/errata/ErrataManager.java b/java/code/src/com/redhat/rhn/manager/errata/ErrataManager.java index 3e3f5c8..4ee5a65 100644 --- a/java/code/src/com/redhat/rhn/manager/errata/ErrataManager.java +++ b/java/code/src/com/redhat/rhn/manager/errata/ErrataManager.java @@ -1274,12 +1274,20 @@ public class ErrataManager extends BaseManager { for (long eid : errata) { NewCloneErrataEvent neve = new NewCloneErrataEvent(chan, eid, user, inheritPackages); + neve.register(); MessageQueue.publish(neve); } }
- - + /** + * Check if the channel has pending asynchronous errata clone jobs + * @param channel channel to check + * @return true if there are pending jobs, false otherwise + */ + public static boolean channelHasPendingAsyncCloneJobs(Channel channel) { + return AsyncErrataCloneCounter.getInstance().channelHasPendingJobs( + channel.getId()); + }
/** * Send errata notifications for a particular errata and channel
spacewalk-commits@lists.fedorahosted.org