From aed5e9dc2a6882139bc38073923be5a3bacfd9d2 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Wed, 2 Oct 2013 09:51:58 -0700 Subject: [PATCH] Add Manage Context framework The managed context framework provides a simple way to add logic to ACS at the various entry points of the system. As threads are launched and ran listeners can be registered for onEntry or onLeave of the managed context. This framework will be used specifically to handle DB transaction checking and setting up the CallContext. This framework is need to transition away from ACS custom AOP to Spring AOP. --- agent/src/com/cloud/agent/Agent.java | 10 +- .../consoleproxy/ConsoleProxyResource.java | 6 +- .../cloudstack/context/CallContext.java | 29 +- .../context/CallContextListener.java | 53 ++++ .../controller/s3/ServiceProvider.java | 6 +- client/tomcatconf/applicationContext.xml.in | 16 ++ .../template/HttpTemplateDownloader.java | 6 +- .../template/S3TemplateDownloader.java | 5 +- .../template/TemplateDownloaderBase.java | 5 +- .../cloudstack/context/ServerContexts.java | 67 ----- .../com/cloud/agent/manager/AgentAttache.java | 5 +- .../cloud/agent/manager/AgentManagerImpl.java | 46 ++- .../manager/ClusteredAgentManagerImpl.java | 19 +- .../agent/manager/DirectAgentAttache.java | 9 +- .../cloud/vm/VirtualMachineManagerImpl.java | 9 +- .../orchestration/NetworkOrchestrator.java | 9 +- .../manager/StorageCacheManagerImpl.java | 7 +- .../cloudstack/storage/LocalHostEndpoint.java | 13 +- .../storage/RemoteHostEndPoint.java | 5 +- .../com/cloud/cluster/ClusterManagerImpl.java | 21 +- .../ClusterServiceServletContainer.java | 6 +- .../cloud/utils/db/ConnectionConcierge.java | 6 +- .../client/ClientTransportProvider.java | 8 +- .../server/ServerTransportProvider.java | 10 +- .../jobs/AsyncJobExecutionContext.java | 4 +- .../jobs/impl/AsyncJobManagerImpl.java | 14 +- .../framework/jobs/impl/AsyncJobMonitor.java | 7 +- framework/managed-context/pom.xml | 36 +++ .../AbstractManagedContextListener.java | 32 +++ .../managed/context/ManagedContext.java | 33 +++ .../context/ManagedContextListener.java | 36 +++ .../context/ManagedContextRunnable.java | 86 ++++++ .../context/ManagedContextTimerTask.java | 37 +++ .../managed/context/ManagedContextUtils.java | 55 ++++ .../context/impl/DefaultManagedContext.java | 155 ++++++++++ .../threadlocal/ManagedThreadLocal.java | 82 ++++++ .../impl/DefaultManagedContextTest.java | 269 ++++++++++++++++++ framework/pom.xml | 1 + .../mom/rabbitmq/RabbitMQEventBus.java | 8 +- .../hypervisor/kvm/resource/KVMHAMonitor.java | 7 +- .../com/cloud/ucs/manager/UcsManagerImpl.java | 6 +- .../lb/ElasticLoadBalancerManagerImpl.java | 6 +- pom.xml | 11 + .../src/com/cloud/alert/AlertManagerImpl.java | 5 +- .../com/cloud/api/ApiAsyncJobDispatcher.java | 16 +- server/src/com/cloud/api/ApiServer.java | 10 +- server/src/com/cloud/api/ApiServlet.java | 16 +- .../deploy/DeploymentPlanningManagerImpl.java | 6 +- .../ha/HighAvailabilityManagerExtImpl.java | 6 +- .../cloud/ha/HighAvailabilityManagerImpl.java | 141 ++++----- .../ExternalDeviceUsageManagerImpl.java | 6 +- .../network/lb/LBHealthCheckManagerImpl.java | 6 +- .../VirtualNetworkApplianceManagerImpl.java | 102 +++---- .../security/SecurityGroupManagerImpl.java | 10 +- .../security/SecurityGroupManagerImpl2.java | 12 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 8 +- .../cloud/projects/ProjectManagerImpl.java | 7 +- .../ResourceLimitManagerImpl.java | 6 +- .../cloud/server/ManagementServerImpl.java | 9 +- .../src/com/cloud/server/StatsCollector.java | 21 +- .../com/cloud/storage/StorageManagerImpl.java | 6 +- .../storage/download/DownloadListener.java | 10 +- .../snapshot/SnapshotSchedulerImpl.java | 9 +- .../cloud/storage/upload/UploadListener.java | 10 +- .../storage/upload/UploadMonitorImpl.java | 6 +- .../cloud/template/TemplateManagerImpl.java | 5 +- .../com/cloud/user/AccountManagerImpl.java | 15 +- .../src/com/cloud/vm/SystemVmLoadScanner.java | 10 +- .../src/com/cloud/vm/UserVmManagerImpl.java | 8 +- .../src/com/cloud/usage/UsageManagerImpl.java | 24 +- .../com/cloud/usage/parser/UsageParser.java | 5 +- utils/pom.xml | 15 +- .../vmware/util/VmwareContextPool.java | 8 +- 73 files changed, 1340 insertions(+), 439 deletions(-) create mode 100644 api/src/org/apache/cloudstack/context/CallContextListener.java delete mode 100644 engine/components-api/src/org/apache/cloudstack/context/ServerContexts.java create mode 100644 framework/managed-context/pom.xml create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/AbstractManagedContextListener.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContext.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextListener.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextRunnable.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextTimerTask.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextUtils.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContext.java create mode 100644 framework/managed-context/src/main/java/org/apache/cloudstack/managed/threadlocal/ManagedThreadLocal.java create mode 100644 framework/managed-context/src/test/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContextTest.java diff --git a/agent/src/com/cloud/agent/Agent.java b/agent/src/com/cloud/agent/Agent.java index f309474fbc5..c713e459262 100755 --- a/agent/src/com/cloud/agent/Agent.java +++ b/agent/src/com/cloud/agent/Agent.java @@ -26,7 +26,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.SynchronousQueue; @@ -36,6 +35,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.naming.ConfigurationException; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.log4j.Logger; import com.cloud.agent.api.AgentControlAnswer; @@ -731,7 +731,7 @@ public class Agent implements HandlerFactory, IAgentControl { } } - public class WatchTask extends TimerTask { + public class WatchTask extends ManagedContextTimerTask { protected Request _request; protected Agent _agent; protected Link _link; @@ -744,7 +744,7 @@ public class Agent implements HandlerFactory, IAgentControl { } @Override - public void run() { + protected void runInContext() { if (s_logger.isTraceEnabled()) { s_logger.trace("Scheduling " + (_request instanceof Response ? "Ping" : "Watch Task")); } @@ -760,7 +760,7 @@ public class Agent implements HandlerFactory, IAgentControl { } } - public class StartupTask extends TimerTask { + public class StartupTask extends ManagedContextTimerTask { protected Link _link; protected volatile boolean cancelled = false; @@ -782,7 +782,7 @@ public class Agent implements HandlerFactory, IAgentControl { } @Override - public synchronized void run() { + protected synchronized void runInContext() { if (!cancelled) { if (s_logger.isInfoEnabled()) { s_logger.info("The startup command is now cancelled"); diff --git a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java index ee5c36176c8..6f49f47a1ed 100644 --- a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java +++ b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java @@ -32,6 +32,7 @@ import java.util.Properties; import javax.naming.ConfigurationException; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.agent.Agent.ExitStatus; @@ -357,8 +358,9 @@ public class ConsoleProxyResource extends ServerResourceBase implements private void launchConsoleProxy(final byte[] ksBits, final String ksPassword, final String encryptorPassword) { final Object resource = this; if (_consoleProxyMain == null) { - _consoleProxyMain = new Thread(new Runnable() { - public void run() { + _consoleProxyMain = new Thread(new ManagedContextRunnable() { + @Override + protected void runInContext() { try { Class consoleProxyClazz = Class.forName("com.cloud.consoleproxy.ConsoleProxy"); try { diff --git a/api/src/org/apache/cloudstack/context/CallContext.java b/api/src/org/apache/cloudstack/context/CallContext.java index 114f626cf95..a9867d3bb70 100644 --- a/api/src/org/apache/cloudstack/context/CallContext.java +++ b/api/src/org/apache/cloudstack/context/CallContext.java @@ -18,8 +18,10 @@ package org.apache.cloudstack.context; import java.util.HashMap; import java.util.Map; +import java.util.Stack; import java.util.UUID; +import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal; import org.apache.log4j.Logger; import org.apache.log4j.NDC; @@ -37,7 +39,14 @@ import com.cloud.utils.exception.CloudRuntimeException; */ public class CallContext { private static final Logger s_logger = Logger.getLogger(CallContext.class); - private static final ThreadLocal s_currentContext = new ThreadLocal(); + private static ManagedThreadLocal s_currentContext = new ManagedThreadLocal(); + private static ManagedThreadLocal> s_currentContextStack = + new ManagedThreadLocal>() { + @Override + protected Stack initialValue() { + return new Stack(); + } + }; private String contextId; private Account account; @@ -115,6 +124,9 @@ public class CallContext { if (s_logger.isTraceEnabled()) { s_logger.trace("Registered: " + callingContext); } + + s_currentContextStack.get().push(callingContext); + return callingContext; } @@ -162,10 +174,15 @@ public class CallContext { return register(user, account); } + public static void unregisterAll() { + while ( unregister() != null ) { + // NOOP + } + } + public static CallContext unregister() { CallContext context = s_currentContext.get(); if (context == null) { - s_logger.debug("No context to remove"); return null; } s_currentContext.remove(); @@ -183,6 +200,14 @@ public class CallContext { s_logger.trace("Popping from NDC: " + contextId); } } + + Stack stack = s_currentContextStack.get(); + stack.pop(); + + if ( ! stack.isEmpty() ) { + s_currentContext.set(stack.peek()); + } + return context; } diff --git a/api/src/org/apache/cloudstack/context/CallContextListener.java b/api/src/org/apache/cloudstack/context/CallContextListener.java new file mode 100644 index 00000000000..9464f3d596e --- /dev/null +++ b/api/src/org/apache/cloudstack/context/CallContextListener.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.context; + +import javax.annotation.PostConstruct; +import javax.inject.Inject; + +import org.apache.cloudstack.managed.context.ManagedContextListener; + +import com.cloud.utils.db.EntityManager; + +public class CallContextListener implements ManagedContextListener { + + @Inject + EntityManager entityMgr; + + @Override + public Object onEnterContext(boolean reentry) { + if ( ! reentry ) { + CallContext.registerSystemCallContextOnceOnly(); + } + + return null; + } + + @Override + public void onLeaveContext(Object unused, boolean reentry) { + if ( ! reentry ) { + CallContext.unregisterAll(); + } + } + + @PostConstruct + public void init() { + CallContext.init(entityMgr); + } +} diff --git a/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java index a0892cc979b..2623efe1f61 100644 --- a/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java +++ b/awsapi/src/com/cloud/bridge/service/controller/s3/ServiceProvider.java @@ -35,6 +35,7 @@ import javax.annotation.PostConstruct; import javax.inject.Inject; import org.apache.axis2.AxisFault; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; import org.springframework.stereotype.Component; @@ -280,10 +281,9 @@ public class ServiceProvider extends ManagerBase { } private TimerTask getHeartbeatTask() { - return new TimerTask() { - + return new ManagedContextTimerTask() { @Override - public void run() { + protected void runInContext() { try { mhost.setLastHeartbeatTime(DateHelper.currentGMTTime()); mhostDao.updateHeartBeat(mhost); diff --git a/client/tomcatconf/applicationContext.xml.in b/client/tomcatconf/applicationContext.xml.in index 9b6636abca5..6dda5c707af 100644 --- a/client/tomcatconf/applicationContext.xml.in +++ b/client/tomcatconf/applicationContext.xml.in @@ -52,6 +52,22 @@ + + + + + + + + + + + + + diff --git a/core/src/com/cloud/storage/template/HttpTemplateDownloader.java b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java index 878961524e3..f0f19629841 100644 --- a/core/src/com/cloud/storage/template/HttpTemplateDownloader.java +++ b/core/src/com/cloud/storage/template/HttpTemplateDownloader.java @@ -40,7 +40,7 @@ import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.log4j.Logger; - +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.Proxy; @@ -52,7 +52,7 @@ import com.cloud.utils.UriUtils; * Download a template file using HTTP * */ -public class HttpTemplateDownloader implements TemplateDownloader { +public class HttpTemplateDownloader extends ManagedContextRunnable implements TemplateDownloader { public static final Logger s_logger = Logger.getLogger(HttpTemplateDownloader.class.getName()); private static final MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager(); @@ -350,7 +350,7 @@ public class HttpTemplateDownloader implements TemplateDownloader { } @Override - public void run() { + protected void runInContext() { try { download(resume, completionCallback); } catch (Throwable t) { diff --git a/core/src/com/cloud/storage/template/S3TemplateDownloader.java b/core/src/com/cloud/storage/template/S3TemplateDownloader.java index 05ed64bfb1e..dd595ea3c97 100644 --- a/core/src/com/cloud/storage/template/S3TemplateDownloader.java +++ b/core/src/com/cloud/storage/template/S3TemplateDownloader.java @@ -50,6 +50,7 @@ import com.amazonaws.services.s3.model.StorageClass; import com.amazonaws.services.s3.transfer.TransferManager; import com.amazonaws.services.s3.transfer.Upload; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.Proxy; @@ -62,7 +63,7 @@ import com.cloud.utils.UriUtils; * Download a template file using HTTP * */ -public class S3TemplateDownloader implements TemplateDownloader { +public class S3TemplateDownloader extends ManagedContextRunnable implements TemplateDownloader { public static final Logger s_logger = Logger.getLogger(S3TemplateDownloader.class.getName()); private static final MultiThreadedHttpConnectionManager s_httpClientManager = new MultiThreadedHttpConnectionManager(); @@ -361,7 +362,7 @@ public class S3TemplateDownloader implements TemplateDownloader { } @Override - public void run() { + protected void runInContext() { try { download(resume, completionCallback); } catch (Throwable t) { diff --git a/core/src/com/cloud/storage/template/TemplateDownloaderBase.java b/core/src/com/cloud/storage/template/TemplateDownloaderBase.java index bdbdd457be1..7cbd4efe02d 100644 --- a/core/src/com/cloud/storage/template/TemplateDownloaderBase.java +++ b/core/src/com/cloud/storage/template/TemplateDownloaderBase.java @@ -18,11 +18,12 @@ package com.cloud.storage.template; import java.io.File; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.storage.StorageLayer; -public abstract class TemplateDownloaderBase implements TemplateDownloader { +public abstract class TemplateDownloaderBase extends ManagedContextRunnable implements TemplateDownloader { private static final Logger s_logger = Logger.getLogger(TemplateDownloaderBase.class); protected String _downloadUrl; @@ -123,7 +124,7 @@ public abstract class TemplateDownloaderBase implements TemplateDownloader { } @Override - public void run() { + protected void runInContext() { try { download(_resume, _callback); } catch (Exception e) { diff --git a/engine/components-api/src/org/apache/cloudstack/context/ServerContexts.java b/engine/components-api/src/org/apache/cloudstack/context/ServerContexts.java deleted file mode 100644 index b9c249ce620..00000000000 --- a/engine/components-api/src/org/apache/cloudstack/context/ServerContexts.java +++ /dev/null @@ -1,67 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -package org.apache.cloudstack.context; - -import org.apache.cloudstack.framework.jobs.AsyncJob; - -import com.cloud.utils.db.Transaction; - -/** - * ServerContextInitializer is responsible for properly setting up the - * contexts that all of the CloudStack code expects. This includes - * - CallContext - * - JobContext - * - TransactionContext - */ -public class ServerContexts { - public static void registerUserContext(long userId, long accountId) { - Transaction txn = Transaction.open(Thread.currentThread().getName()); - CallContext context = CallContext.register(userId, accountId); - context.putContextParameter("Transaction", txn); -// AsyncJobExecutionContext.registerPseudoExecutionContext(userId, accountId); - } - - public static void unregisterUserContext() { - CallContext context = CallContext.unregister(); - if (context != null) { -// AsyncJobExecutionContext.unregister(); - Transaction txn = (Transaction)context.getContextParameter("Transaction"); - txn.close(Thread.currentThread().getName()); - } - } - - /** - * Use this method to initialize the internal background threads. - */ - public static void registerSystemContext() { - Transaction txn = Transaction.open(Thread.currentThread().getName()); - CallContext context = CallContext.registerSystemCallContextOnceOnly(); - context.putContextParameter("Transaction", txn); -// AsyncJobExecutionContext.registerPseudoExecutionContext(Account.ACCOUNT_ID_SYSTEM, User.UID_SYSTEM); - } - - public static void unregisterSystemContext() { - CallContext context = CallContext.unregister(); -// AsyncJobExecutionContext.unregister(); - Transaction txn = (Transaction)context.getContextParameter("Transaction"); - txn.close(Thread.currentThread().getName()); - } - - public static void registerJobContext(long userId, long accountId, AsyncJob job) { - CallContext.register(userId, accountId); - } -} diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java index 67deba0d648..5b1007b26f0 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentAttache.java @@ -31,6 +31,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.agent.Listener; @@ -497,14 +498,14 @@ public abstract class AgentAttache { */ protected abstract boolean isClosed(); - protected class Alarm implements Runnable { + protected class Alarm extends ManagedContextRunnable { long _seq; public Alarm(long seq) { _seq = seq; } @Override - public void run() { + protected void runInContext() { try { Listener listener = unregisterListener(_seq); if (listener != null) { diff --git a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java index 51f6d72109e..42020153448 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/AgentManagerImpl.java @@ -38,13 +38,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -843,7 +842,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return true; } - protected class DisconnectTask implements Runnable { + protected class DisconnectTask extends ManagedContextRunnable { AgentAttache _attache; Status.Event _event; boolean _investigate; @@ -855,7 +854,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } @Override - public void run() { + protected void runInContext() { try { if (_investigate == true) { handleDisconnectWithInvestigation(_attache, _event); @@ -1017,7 +1016,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl return attache; } - protected class SimulateStartTask implements Runnable { + protected class SimulateStartTask extends ManagedContextRunnable { ServerResource resource; Map details; long id; @@ -1029,8 +1028,7 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { try { if (s_logger.isDebugEnabled()) { s_logger.debug("Simulating start for resource " + resource.getName() + " id " + id); @@ -1054,13 +1052,11 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl } } catch (Exception e) { s_logger.warn("Unable to simulate start on resource " + id + " name " + resource.getName(), e); - } finally { - ServerContexts.unregisterSystemContext(); } } } - protected class HandleAgentConnectTask implements Runnable { + protected class HandleAgentConnectTask extends ManagedContextRunnable { Link _link; Command[] _cmds; Request _request; @@ -1071,22 +1067,16 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _request = request; } - @Override - public void run() { - ServerContexts.registerSystemContext(); - try { - _request.logD("Processing the first command "); - StartupCommand[] startups = new StartupCommand[_cmds.length]; - for (int i = 0; i < _cmds.length; i++) { - startups[i] = (StartupCommand)_cmds[i]; - } + protected void runInContext() { + _request.logD("Processing the first command "); + StartupCommand[] startups = new StartupCommand[_cmds.length]; + for (int i = 0; i < _cmds.length; i++) { + startups[i] = (StartupCommand)_cmds[i]; + } - AgentAttache attache = handleConnectedAgent(_link, startups, _request); - if (attache == null) { - s_logger.warn("Unable to create attache for agent: " + _request); - } - } finally { - ServerContexts.unregisterSystemContext(); + AgentAttache attache = handleConnectedAgent(_link, startups, _request); + if (attache == null) { + s_logger.warn("Unable to create attache for agent: " + _request); } } } @@ -1439,9 +1429,9 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl _pingMap.put(agentId, InaccurateClock.getTimeInSeconds()); } - protected class MonitorTask implements Runnable { + protected class MonitorTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { s_logger.trace("Agent Monitor is started."); try { diff --git a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java index 76e1d8e33b6..48f096ade22 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java +++ b/engine/orchestration/src/com/cloud/agent/manager/ClusteredAgentManagerImpl.java @@ -32,7 +32,6 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; @@ -51,6 +50,8 @@ import com.google.gson.Gson; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.agent.AgentManager; @@ -231,9 +232,9 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } } - private class DirectAgentScanTimerTask extends TimerTask { + private class DirectAgentScanTimerTask extends ManagedContextTimerTask { @Override - public void run() { + protected void runInContext() { try { runDirectAgentScanTimerTask(); } catch (Throwable e) { @@ -746,7 +747,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust _timer.schedule(new AgentLoadBalancerTask(), 30000); } - public class AgentLoadBalancerTask extends TimerTask { + public class AgentLoadBalancerTask extends ManagedContextTimerTask { protected volatile boolean cancelled = false; public AgentLoadBalancerTask() { @@ -764,7 +765,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } @Override - public synchronized void run() { + protected synchronized void runInContext() { try { if (!cancelled) { startRebalanceAgents(); @@ -925,9 +926,9 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } private Runnable getTransferScanTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { try { if (s_logger.isTraceEnabled()) { s_logger.trace("Clustered agent transfer scan check, management server id:" + _nodeId); @@ -1173,7 +1174,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } - protected class RebalanceTask implements Runnable { + protected class RebalanceTask extends ManagedContextRunnable { Long hostId = null; Long currentOwnerId = null; Long futureOwnerId = null; @@ -1186,7 +1187,7 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust } @Override - public void run() { + protected void runInContext() { try { if (s_logger.isDebugEnabled()) { s_logger.debug("Rebalancing host id=" + hostId); diff --git a/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java b/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java index 5b5d8d21289..2808c6af91a 100755 --- a/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java +++ b/engine/orchestration/src/com/cloud/agent/manager/DirectAgentAttache.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.agent.api.Answer; @@ -127,9 +128,9 @@ public class DirectAgentAttache extends AgentAttache { } } - protected class PingTask implements Runnable { + protected class PingTask extends ManagedContextRunnable { @Override - public synchronized void run() { + protected synchronized void runInContext() { try { ServerResource resource = _resource; @@ -160,7 +161,7 @@ public class DirectAgentAttache extends AgentAttache { } - protected class Task implements Runnable { + protected class Task extends ManagedContextRunnable { Request _req; public Task(Request req) { @@ -168,7 +169,7 @@ public class DirectAgentAttache extends AgentAttache { } @Override - public void run() { + protected void runInContext() { long seq = _req.getSequence(); try { ServerResource resource = _resource; diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index 560bab26fff..8bf419f1a65 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -47,6 +47,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; @@ -1835,9 +1836,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - protected class CleanupTask implements Runnable { + protected class CleanupTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { s_logger.trace("VM Operation Thread Running"); try { _workDao.cleanup(VmOpCleanupWait.value()); @@ -2588,9 +2589,9 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } } - protected class TransitionTask implements Runnable { + protected class TransitionTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { GlobalLock lock = GlobalLock.getInternLock("TransitionChecking"); if (lock == null) { s_logger.debug("Couldn't get the global lock"); diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 0b13fb40003..3c4b1ed5e72 100755 --- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -37,15 +37,14 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.region.PortableIpDao; import com.cloud.agent.AgentManager; @@ -2195,10 +2194,9 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return result; } - public class NetworkGarbageCollector implements Runnable { + public class NetworkGarbageCollector extends ManagedContextRunnable { @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { GlobalLock gcLock = GlobalLock.getInternLock("Network.GC.Lock"); try { if (gcLock.lock(3)) { @@ -2210,7 +2208,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } finally { gcLock.releaseRef(); - ServerContexts.unregisterSystemContext(); } } diff --git a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java index 7f335c53315..bb8d67d321f 100644 --- a/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java +++ b/engine/storage/cache/src/org/apache/cloudstack/storage/cache/manager/StorageCacheManagerImpl.java @@ -45,6 +45,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.StorageCacheManager; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.cache.allocator.StorageCacheAllocator; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; @@ -145,10 +146,10 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager { return true; } - protected class CacheReplacementRunner implements Runnable { + protected class CacheReplacementRunner extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { GlobalLock replacementLock = null; try { replacementLock = GlobalLock.getInternLock("storageCacheMgr.replacement"); @@ -271,4 +272,4 @@ public class StorageCacheManagerImpl implements StorageCacheManager, Manager { public boolean deleteCacheObject(DataObject data) { return data.getDataStore().delete(data); } -} \ No newline at end of file +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java index 83d34a07f4a..53803bf594c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/LocalHostEndpoint.java @@ -21,24 +21,23 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import com.cloud.configuration.Config; -import com.cloud.utils.component.ComponentContext; +import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.framework.config.dao.ConfigurationDaoImpl; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.DownloadCommand; import org.apache.cloudstack.storage.resource.LocalNfsSecondaryStorageResource; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.configuration.Config; import com.cloud.resource.ServerResource; +import com.cloud.utils.component.ComponentContext; import com.cloud.utils.net.NetUtils; -import javax.inject.Inject; - public class LocalHostEndpoint implements EndPoint { private ScheduledExecutorService executor; protected ServerResource resource; @@ -97,7 +96,7 @@ public class LocalHostEndpoint implements EndPoint { return new Answer(cmd, false, "unsupported command:" + cmd.toString()); } - private class CmdRunner implements Runnable { + private class CmdRunner extends ManagedContextRunnable { final Command cmd; final AsyncCompletionCallback callback; @@ -107,7 +106,7 @@ public class LocalHostEndpoint implements EndPoint { } @Override - public void run() { + protected void runInContext() { Answer answer = sendMessage(cmd); callback.complete(answer); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java index 369381358a8..3cae2b95f1d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java +++ b/engine/storage/src/org/apache/cloudstack/storage/RemoteHostEndPoint.java @@ -26,6 +26,7 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -104,7 +105,7 @@ public class RemoteHostEndPoint implements EndPoint { throw new CloudRuntimeException("Failed to send command, due to Agent:" + getId() + ", " + errMsg); } - private class CmdRunner implements Listener, Runnable { + private class CmdRunner extends ManagedContextRunnable implements Listener { final AsyncCompletionCallback callback; Answer answer; @@ -162,7 +163,7 @@ public class RemoteHostEndPoint implements EndPoint { } @Override - public void run() { + protected void runInContext() { callback.complete(answer); } } diff --git a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java index 0f1cf9da487..56d405e98e9 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterManagerImpl.java @@ -48,6 +48,7 @@ import org.apache.log4j.Logger; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.cluster.dao.ManagementServerHostDao; @@ -217,18 +218,18 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C } private Runnable getClusterPduSendingTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { onSendingClusterPdu(); } }; } private Runnable getClusterPduNotificationTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { onNotifyingClusterPdu(); } }; @@ -289,9 +290,9 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C if(pdu == null) continue; - _executor.execute(new Runnable() { + _executor.execute(new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { if(pdu.getPduType() == ClusterServicePdu.PDU_TYPE_RESPONSE) { ClusterServiceRequestPdu requestPdu = popRequestPdu(pdu.getAckSequenceId()); if(requestPdu != null) { @@ -528,9 +529,9 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C } private Runnable getHeartbeatTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { Transaction txn = Transaction.open("ClusterHeartbeat"); try { Profiler profiler = new Profiler(); @@ -636,9 +637,9 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager, C } private Runnable getNotificationTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { while(true) { synchronized(_notificationMsgs) { try { diff --git a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletContainer.java b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletContainer.java index def3e178116..019d83de8ac 100644 --- a/framework/cluster/src/com/cloud/cluster/ClusterServiceServletContainer.java +++ b/framework/cluster/src/com/cloud/cluster/ClusterServiceServletContainer.java @@ -22,6 +22,7 @@ import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.http.ConnectionClosedException; import org.apache.http.HttpException; import org.apache.http.impl.DefaultConnectionReuseStrategy; @@ -129,8 +130,9 @@ public class ClusterServiceServletContainer { final DefaultHttpServerConnection conn = new DefaultHttpServerConnection(); conn.bind(socket, _params); - _executor.execute(new Runnable() { - public void run() { + _executor.execute(new ManagedContextRunnable() { + @Override + protected void runInContext() { HttpContext context = new BasicHttpContext(null); try { while(!Thread.interrupted() && conn.isOpen()) { diff --git a/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java b/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java index 029433453bf..c3c24f94766 100644 --- a/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java +++ b/framework/db/src/com/cloud/utils/db/ConnectionConcierge.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.management.StandardMBean; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -198,10 +199,9 @@ public class ConnectionConcierge { _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("ConnectionConcierge")); - _executor.scheduleAtFixedRate(new Runnable() { - + _executor.scheduleAtFixedRate(new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { s_logger.trace("connection concierge keep alive task"); for (Map.Entry entry : _conns.entrySet()) { ConnectionConcierge concierge = entry.getValue(); diff --git a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java index 023b3181b20..923578cf5f1 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/client/ClientTransportProvider.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.framework.serializer.MessageSerializer; import org.apache.cloudstack.framework.transport.TransportEndpoint; import org.apache.cloudstack.framework.transport.TransportEndpointSite; import org.apache.cloudstack.framework.transport.TransportProvider; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -62,10 +63,9 @@ public class ClientTransportProvider implements TransportProvider { _executor = Executors.newFixedThreadPool(_poolSize, new NamedThreadFactory("Transport-Worker")); _connection = new ClientTransportConnection(this); - _executor.execute(new Runnable() { - - @Override - public void run() { + _executor.execute(new ManagedContextRunnable() { + @Override + protected void runInContext() { try { _connection.connect(_serverAddress, _serverPort); } catch(Throwable e) { diff --git a/framework/ipc/src/org/apache/cloudstack/framework/server/ServerTransportProvider.java b/framework/ipc/src/org/apache/cloudstack/framework/server/ServerTransportProvider.java index b19a7c9265f..45c3e2a41d7 100644 --- a/framework/ipc/src/org/apache/cloudstack/framework/server/ServerTransportProvider.java +++ b/framework/ipc/src/org/apache/cloudstack/framework/server/ServerTransportProvider.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.framework.transport.TransportEndpoint; import org.apache.cloudstack.framework.transport.TransportEndpointSite; import org.apache.cloudstack.framework.transport.TransportPdu; import org.apache.cloudstack.framework.transport.TransportProvider; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -132,11 +133,10 @@ public class ServerTransportProvider implements TransportProvider { @Override public void requestSiteOutput(final TransportEndpointSite site) { - _executor.execute(new Runnable() { - - @Override - public void run() { - try { + _executor.execute(new ManagedContextRunnable() { + @Override + protected void runInContext() { + try { site.processOutput(); site.ackOutputProcessSignal(); } catch(Throwable e) { diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java index 01365939127..595800d2524 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/AsyncJobExecutionContext.java @@ -17,12 +17,12 @@ package org.apache.cloudstack.framework.jobs; import org.apache.log4j.Logger; - import org.apache.cloudstack.framework.jobs.dao.AsyncJobJoinMapDao; import org.apache.cloudstack.framework.jobs.impl.AsyncJobJoinMapVO; import org.apache.cloudstack.framework.jobs.impl.JobSerializerHelper; import org.apache.cloudstack.framework.jobs.impl.SyncQueueItem; import org.apache.cloudstack.jobs.JobInfo; +import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; @@ -39,7 +39,7 @@ public class AsyncJobExecutionContext { _joinMapDao = joinMapDao; } - private static ThreadLocal s_currentExectionContext = new ThreadLocal(); + private static ManagedThreadLocal s_currentExectionContext = new ManagedThreadLocal(); public AsyncJobExecutionContext() { } diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java index 2ddb1158c8c..93d50c11233 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java @@ -36,7 +36,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; @@ -54,6 +53,7 @@ import org.apache.cloudstack.framework.messagebus.MessageDetector; import org.apache.cloudstack.framework.messagebus.PublishScope; import org.apache.cloudstack.jobs.JobInfo; import org.apache.cloudstack.jobs.JobInfo.Status; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.cluster.ClusterManagerListener; @@ -490,9 +490,9 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, } private Runnable getExecutorRunnable(final AsyncJob job) { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { Transaction txn = null; long runNumber = getJobRunNumber(); @@ -687,9 +687,9 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, } private Runnable getHeartbeatTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { Transaction txn = Transaction.open("AsyncJobManagerImpl.getHeartbeatTask"); try { List l = _queueMgr.dequeueFromAny(getMsid(), MAX_ONETIME_SCHEDULE_SIZE); @@ -724,9 +724,9 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager, @DB private Runnable getGCTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { GlobalLock scanLock = GlobalLock.getInternLock("AsyncJobManagerGC"); try { if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { diff --git a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobMonitor.java b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobMonitor.java index ad0da35adb3..8ea75289dfd 100644 --- a/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobMonitor.java +++ b/framework/jobs/src/org/apache/cloudstack/framework/jobs/impl/AsyncJobMonitor.java @@ -26,12 +26,12 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageDispatcher; import org.apache.cloudstack.framework.messagebus.MessageHandler; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import com.cloud.utils.component.ManagerBase; @@ -97,10 +97,9 @@ public class AsyncJobMonitor extends ManagerBase { throws ConfigurationException { _messageBus.subscribe(AsyncJob.Topics.JOB_HEARTBEAT, MessageDispatcher.getDispatcher(this)); - _timer.scheduleAtFixedRate(new TimerTask() { - + _timer.scheduleAtFixedRate(new ManagedContextTimerTask() { @Override - public void run() { + protected void runInContext() { heartbeat(); } diff --git a/framework/managed-context/pom.xml b/framework/managed-context/pom.xml new file mode 100644 index 00000000000..b4a9d83a005 --- /dev/null +++ b/framework/managed-context/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + cloud-framework-managed-context + Apache CloudStack Framework - Managed Context + + org.apache.cloudstack + cloud-maven-standard + 4.3.0-SNAPSHOT + ../../maven-standard/pom.xml + + + + org.slf4j + slf4j-api + + + diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/AbstractManagedContextListener.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/AbstractManagedContextListener.java new file mode 100644 index 00000000000..21f63a68f81 --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/AbstractManagedContextListener.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +public class AbstractManagedContextListener implements ManagedContextListener { + + @Override + public T onEnterContext(boolean reentry) { + return null; + } + + @Override + public void onLeaveContext(T data, boolean reentry) { + } + +} \ No newline at end of file diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContext.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContext.java new file mode 100644 index 00000000000..5023725d0de --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContext.java @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +import java.util.concurrent.Callable; + +public interface ManagedContext { + + public void registerListener(ManagedContextListener listener); + + public void unregisterListener(ManagedContextListener listener); + + public void runWithContext(Runnable run); + + public T callWithContext(Callable callable) throws Exception; + +} \ No newline at end of file diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextListener.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextListener.java new file mode 100644 index 00000000000..2f85a5f69ab --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextListener.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +public interface ManagedContextListener { + + /** + * @param reentry True if listener is being invoked in a nested context + * @return + */ + public T onEnterContext(boolean reentry); + + + /** + * @param data The data returned from the onEnterContext call + * @param reentry True if listener is being invoked in a nested context + */ + public void onLeaveContext(T data, boolean reentry); + +} diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextRunnable.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextRunnable.java new file mode 100644 index 00000000000..2f3d0c8a71f --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextRunnable.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +import org.apache.cloudstack.managed.context.impl.DefaultManagedContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class ManagedContextRunnable implements Runnable { + + private static final int SLEEP_COUNT = 120; + + private static final Logger log = LoggerFactory.getLogger(ManagedContextRunnable.class); + private static final ManagedContext DEFAULT_MANAGED_CONTEXT = new DefaultManagedContext(); + private static ManagedContext context; + private static boolean managedContext = false; + + + /* This is slightly dirty, but the idea is that we only save the ManagedContext + * in a static global. Any ManagedContextListener can be a fully managed object + * and not have to rely on global statics + */ + public static ManagedContext initializeGlobalContext(ManagedContext context) { + setManagedContext(true); + return ManagedContextRunnable.context = context; + } + + @Override + final public void run() { + getContext().runWithContext(new Runnable() { + @Override + public void run() { + runInContext(); + } + }); + } + + protected abstract void runInContext(); + + protected ManagedContext getContext() { + if ( ! managedContext ) + return DEFAULT_MANAGED_CONTEXT; + + for ( int i = 0 ; i < SLEEP_COUNT ; i++ ) { + if ( context == null ) { + try { + Thread.sleep(1000); + + if ( context == null ) + log.info("Sleeping until ManagedContext becomes available"); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } else { + return context; + } + } + + throw new RuntimeException("Failed to obtain ManagedContext"); + } + + public static boolean isManagedContext() { + return managedContext; + } + + public static void setManagedContext(boolean managedContext) { + ManagedContextRunnable.managedContext = managedContext; + } + +} \ No newline at end of file diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextTimerTask.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextTimerTask.java new file mode 100644 index 00000000000..894d27c7c42 --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextTimerTask.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +import java.util.TimerTask; + +public abstract class ManagedContextTimerTask extends TimerTask { + + @Override + public final void run() { + new ManagedContextRunnable() { + @Override + protected void runInContext() { + ManagedContextTimerTask.this.runInContext(); + } + }.run(); + } + + protected abstract void runInContext(); + +} diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextUtils.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextUtils.java new file mode 100644 index 00000000000..75bb2056f02 --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/ManagedContextUtils.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context; + +public class ManagedContextUtils { + + private static final ThreadLocal OWNER = new ThreadLocal(); + + public static boolean setAndCheckOwner(Object owner) { + if ( OWNER.get() == null ) { + OWNER.set(owner); + return true; + } + + return false; + } + + public static boolean clearOwner(Object owner) { + if ( OWNER.get() == owner ) { + OWNER.remove(); + return true; + } + + return false; + } + + public static boolean isInContext() { + return OWNER.get() != null; + } + + public static void rethrowException(Throwable t) { + if ( t instanceof RuntimeException ) { + throw (RuntimeException)t; + } else if ( t instanceof Error ) { + throw (Error)t; + } + } + +} diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContext.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContext.java new file mode 100644 index 00000000000..6f5cbc98bec --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContext.java @@ -0,0 +1,155 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context.impl; + +import java.util.List; +import java.util.Stack; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.apache.cloudstack.managed.context.ManagedContext; +import org.apache.cloudstack.managed.context.ManagedContextListener; +import org.apache.cloudstack.managed.context.ManagedContextUtils; +import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DefaultManagedContext implements ManagedContext { + + private static final Logger log = LoggerFactory.getLogger(DefaultManagedContext.class); + + List> listeners = + new CopyOnWriteArrayList>(); + + @Override + public void registerListener(ManagedContextListener listener) { + listeners.add(listener); + } + + @Override + public void unregisterListener(ManagedContextListener listener) { + listeners.remove(listener); + } + + @Override + public void runWithContext(final Runnable run) { + try { + callWithContext(new Callable() { + @Override + public Object call() throws Exception { + run.run(); + return null; + } + }); + } catch (Exception e) { + /* Only care about non-checked exceptions + * as the nature of runnable prevents checked + * exceptions from happening + */ + ManagedContextUtils.rethrowException(e); + } + } + + @SuppressWarnings("unchecked") + @Override + public T callWithContext(Callable callable) throws Exception { + Object owner = new Object(); + + Stack invocations = new Stack(); + boolean reentry = ! ManagedContextUtils.setAndCheckOwner(owner); + Throwable firstError = null; + + try { + for ( ManagedContextListener listener : listeners ) { + Object data = null; + + try { + data = listener.onEnterContext(reentry); + } catch ( Throwable t ) { + /* If one listener fails, still call all other listeners + * and then we will call onLeaveContext for all + */ + if ( firstError == null ) { + firstError = t; + } + log.error("Failed onEnterContext for listener [{}]", listener, t); + } + + /* Stack data structure is used because in between onEnter and onLeave + * the listeners list could have changed + */ + invocations.push(new ListenerInvocation((ManagedContextListener) listener, data)); + } + + try { + if ( firstError == null ) { + /* Only call if all the listeners didn't blow up on onEnterContext */ + return callable.call(); + } else { + throwException(firstError); + return null; + } + } finally { + Throwable lastError = null; + + while ( ! invocations.isEmpty() ) { + ListenerInvocation invocation = invocations.pop(); + try { + invocation.listener.onLeaveContext(invocation.data, reentry); + } catch ( Throwable t ) { + lastError = t; + log.error("Failed onLeaveContext for listener [{}]", invocation.listener, t); + } + } + + if ( firstError == null && lastError != null ) { + throwException(lastError); + } + } + } finally { + if ( ManagedContextUtils.clearOwner(owner) ) + ManagedThreadLocal.reset(); + } + }; + + protected void throwException(Throwable t) throws Exception { + ManagedContextUtils.rethrowException(t); + if ( t instanceof Exception ) { + throw (Exception)t; + } + } + public List> getListeners() { + return listeners; + } + + public void setListeners(List> listeners) { + this.listeners = new CopyOnWriteArrayList>(listeners); + } + + private static class ListenerInvocation { + ManagedContextListener listener; + Object data; + + public ListenerInvocation(ManagedContextListener listener, Object data) { + super(); + this.listener = listener; + this.data = data; + } + } +} diff --git a/framework/managed-context/src/main/java/org/apache/cloudstack/managed/threadlocal/ManagedThreadLocal.java b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/threadlocal/ManagedThreadLocal.java new file mode 100644 index 00000000000..bde535cc179 --- /dev/null +++ b/framework/managed-context/src/main/java/org/apache/cloudstack/managed/threadlocal/ManagedThreadLocal.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.threadlocal; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.cloudstack.managed.context.ManagedContextUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ManagedThreadLocal extends ThreadLocal { + + private static final ThreadLocal> MANAGED_THREAD_LOCAL = new ThreadLocal>() { + @Override + protected Map initialValue() { + return new HashMap(); + } + }; + + private static boolean VALIDATE_CONTEXT = false; + private static final Logger log = LoggerFactory.getLogger(ManagedThreadLocal.class); + + @SuppressWarnings("unchecked") + @Override + public T get() { + validateInContext(this); + Map map = MANAGED_THREAD_LOCAL.get(); + Object result = map.get(this); + if ( result == null ) { + result = initialValue(); + map.put(this, result); + } + return (T) result; + } + + @Override + public void set(T value) { + validateInContext(this); + Map map = MANAGED_THREAD_LOCAL.get(); + map.put(this, value); + } + + public static void reset() { + validateInContext(null); + MANAGED_THREAD_LOCAL.remove(); + } + + @Override + public void remove() { + Map map = MANAGED_THREAD_LOCAL.get(); + map.remove(this); + } + + private static void validateInContext(Object tl) { + if ( VALIDATE_CONTEXT && ! ManagedContextUtils.isInContext() ) { + String msg = "Using a managed thread local in a non managed context this WILL cause errors at runtime. TL [" + + tl + "]"; + log.error(msg, new IllegalStateException(msg)); + } + } + + public static void setValidateInContext(boolean validate) { + VALIDATE_CONTEXT = validate; + } +} diff --git a/framework/managed-context/src/test/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContextTest.java b/framework/managed-context/src/test/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContextTest.java new file mode 100644 index 00000000000..aa2d2e6dca0 --- /dev/null +++ b/framework/managed-context/src/test/java/org/apache/cloudstack/managed/context/impl/DefaultManagedContextTest.java @@ -0,0 +1,269 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.managed.context.impl; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Callable; + +import org.apache.cloudstack.managed.context.ManagedContextListener; +import org.apache.cloudstack.managed.threadlocal.ManagedThreadLocal; +import org.junit.Before; +import org.junit.Test; + +public class DefaultManagedContextTest { + + DefaultManagedContext context; + + @Before + public void init() { + ManagedThreadLocal.setValidateInContext(false); + + context = new DefaultManagedContext(); + } + + @Test + public void testCallable() throws Exception { + assertEquals(5, context.callWithContext(new Callable() { + @Override + public Integer call() throws Exception { + return 5; + } + }).intValue()); + } + + @Test + public void testRunnable() throws Exception { + final List touch = new ArrayList(); + + context.runWithContext(new Runnable() { + @Override + public void run() { + touch.add(new Object()); + } + }); + + assertEquals(1, touch.size()); + } + + @Test + public void testGoodListeners() throws Exception { + final List touch = new ArrayList(); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter"); + return "hi"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave"); + assertEquals("hi", data); + } + }); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter1"); + return "hi"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave1"); + assertEquals("hi", data); + } + }); + + assertEquals(5, context.callWithContext(new Callable() { + @Override + public Integer call() throws Exception { + return 5; + } + }).intValue()); + + assertEquals("enter", touch.get(0)); + assertEquals("enter1", touch.get(1)); + assertEquals("leave1", touch.get(2)); + assertEquals("leave", touch.get(3)); + } + + @Test + public void testBadListeners() throws Exception { + final List touch = new ArrayList(); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter"); + throw new RuntimeException("I'm a failure"); + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave"); + assertNull(data); + } + }); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter1"); + return "hi"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave1"); + assertEquals("hi", data); + } + }); + + try { + context.callWithContext(new Callable() { + @Override + public Integer call() throws Exception { + return 5; + } + }).intValue(); + + fail(); + } catch ( Throwable t ) { + assertTrue(t instanceof RuntimeException); + assertEquals("I'm a failure", t.getMessage()); + } + + assertEquals("enter", touch.get(0)); + assertEquals("enter1", touch.get(1)); + assertEquals("leave1", touch.get(2)); + assertEquals("leave", touch.get(3)); + } + + @Test + public void testBadInvocation() throws Exception { + final List touch = new ArrayList(); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter"); + return "hi"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave"); + assertEquals("hi", data); + } + }); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter1"); + return "hi1"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave1"); + assertEquals("hi1", data); + } + }); + + try { + context.callWithContext(new Callable() { + @Override + public Integer call() throws Exception { + throw new RuntimeException("I'm a failure"); + } + }).intValue(); + + fail(); + } catch ( Throwable t ) { + assertTrue(t.getMessage(), t instanceof RuntimeException); + assertEquals("I'm a failure", t.getMessage()); + } + + assertEquals("enter", touch.get(0)); + assertEquals("enter1", touch.get(1)); + assertEquals("leave1", touch.get(2)); + assertEquals("leave", touch.get(3)); + } + + @Test + public void testBadListernInExit() throws Exception { + final List touch = new ArrayList(); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter"); + return "hi"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave"); + assertEquals("hi", data); + + throw new RuntimeException("I'm a failure"); + } + }); + + context.registerListener(new ManagedContextListener() { + @Override + public Object onEnterContext(boolean reentry) { + touch.add("enter1"); + return "hi1"; + } + + @Override + public void onLeaveContext(Object data, boolean reentry) { + touch.add("leave1"); + assertEquals("hi1", data); + } + }); + + try { + context.callWithContext(new Callable() { + @Override + public Integer call() throws Exception { + return 5; + } + }).intValue(); + + fail(); + } catch ( Throwable t ) { + assertTrue(t.getMessage(), t instanceof RuntimeException); + assertEquals("I'm a failure", t.getMessage()); + } + + assertEquals("enter", touch.get(0)); + assertEquals("enter1", touch.get(1)); + assertEquals("leave1", touch.get(2)); + assertEquals("leave", touch.get(3)); + } +} diff --git a/framework/pom.xml b/framework/pom.xml index 1764076d498..4ea2df14cf2 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -37,5 +37,6 @@ cluster db config + managed-context diff --git a/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java index 1c0c6bef6f2..478c8d7aaed 100644 --- a/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java +++ b/plugins/event-bus/rabbitmq/src/org/apache/cloudstack/mom/rabbitmq/RabbitMQEventBus.java @@ -20,7 +20,9 @@ package org.apache.cloudstack.mom.rabbitmq; import com.rabbitmq.client.*; + import org.apache.cloudstack.framework.events.*; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import com.cloud.utils.Ternary; @@ -28,6 +30,7 @@ import com.cloud.utils.component.ManagerBase; import javax.ejb.Local; import javax.naming.ConfigurationException; + import java.io.IOException; import java.net.ConnectException; import java.util.Map; @@ -493,12 +496,13 @@ public class RabbitMQEventBus extends ManagerBase implements EventBus { } // retry logic to connect back to AMQP server after loss of connection - private class ReconnectionTask implements Runnable { + private class ReconnectionTask extends ManagedContextRunnable { boolean connected = false; Connection connection = null; - public void run() { + @Override + protected void runInContext() { while (!connected) { try { diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/KVMHAMonitor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/KVMHAMonitor.java index 0e4d9eea8ac..1117110e2b8 100644 --- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/KVMHAMonitor.java +++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/KVMHAMonitor.java @@ -20,7 +20,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; + +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; + import com.cloud.utils.script.Script; import org.libvirt.Connect; @@ -68,10 +71,10 @@ public class KVMHAMonitor extends KVMHABase implements Runnable { } } - private class Monitor implements Runnable { + private class Monitor extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { synchronized (_storagePool) { for (String uuid : _storagePool.keySet()) { NfsStoragePool primaryStoragePool = _storagePool.get(uuid); diff --git a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java index 8da9da086af..9dfe91d5124 100755 --- a/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java +++ b/plugins/hypervisors/ucs/src/com/cloud/ucs/manager/UcsManagerImpl.java @@ -31,7 +31,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.api.AddUcsManagerCmd; import org.apache.cloudstack.api.AssociateUcsProfileToBladeCmd; import org.apache.cloudstack.api.DeleteUcsManagerCmd; @@ -43,6 +42,7 @@ import org.apache.cloudstack.api.response.UcsBladeResponse; import org.apache.cloudstack.api.response.UcsManagerResponse; import org.apache.cloudstack.api.response.UcsProfileResponse; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.configuration.Config; import com.cloud.dc.ClusterDetailsDao; @@ -98,7 +98,7 @@ public class UcsManagerImpl implements UcsManager { private ScheduledExecutorService syncBladesExecutor; private int syncBladeInterval; - private class SyncBladesThread implements Runnable { + private class SyncBladesThread extends ManagedContextRunnable { private void discoverNewBlades(Map previous, Map now, UcsManagerVO mgr) { @@ -156,7 +156,7 @@ public class UcsManagerImpl implements UcsManager { } @Override - public void run() { + protected void runInContext() { try { List mgrs = ucsDao.listAll(); for (UcsManagerVO mgr : mgrs) { diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 6b719eb1476..3f8fc5c6f9d 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -36,11 +36,11 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.api.command.user.loadbalancer.CreateLoadBalancerRuleCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; @@ -749,9 +749,9 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast _gcCandidateElbVmIds = currentGcCandidates; } - public class CleanupThread implements Runnable { + public class CleanupThread extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { garbageCollectUnusedElbVms(); } diff --git a/pom.xml b/pom.xml index 1c85bc43d30..d8c6f405d7f 100644 --- a/pom.xml +++ b/pom.xml @@ -172,6 +172,7 @@ test client services + maven-standard @@ -380,6 +381,16 @@ wsdl4j 1.4 + + org.slf4j + slf4j-api + 1.7.5 + + + org.slf4j + slf4j-log4j12 + 1.7.5 + diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 6f5d25a61c1..ed0c9fdcb46 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -48,6 +48,7 @@ import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; @@ -455,9 +456,9 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi } - class CapacityChecker extends TimerTask { + class CapacityChecker extends ManagedContextTimerTask { @Override - public void run() { + protected void runInContext() { try { s_logger.debug("Running Capacity Checker ... "); checkForAlerts(); diff --git a/server/src/com/cloud/api/ApiAsyncJobDispatcher.java b/server/src/com/cloud/api/ApiAsyncJobDispatcher.java index 7092ef3779f..22ccb891e62 100644 --- a/server/src/com/cloud/api/ApiAsyncJobDispatcher.java +++ b/server/src/com/cloud/api/ApiAsyncJobDispatcher.java @@ -36,6 +36,7 @@ import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobDispatcher; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.jobs.JobInfo; +import org.apache.cloudstack.managed.context.ManagedContext; import com.cloud.user.Account; import com.cloud.user.User; @@ -51,12 +52,23 @@ public class ApiAsyncJobDispatcher extends AdapterBase implements AsyncJobDispat @Inject private AsyncJobManager _asyncJobMgr; @Inject private EntityManager _entityMgr; + @Inject + ManagedContext _managedContext; public ApiAsyncJobDispatcher() { } - @Override - public void runJob(AsyncJob job) { + @Override + public void runJob(final AsyncJob job) { + _managedContext.runWithContext(new Runnable() { + @Override + public void run() { + runJobInContext(job); + } + }); + } + + protected void runJobInContext(AsyncJob job) { BaseAsyncCmd cmdObj = null; try { Class cmdClass = Class.forName(job.getCmd()); diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java index 26789e3a81a..b73045d5fce 100755 --- a/server/src/com/cloud/api/ApiServer.java +++ b/server/src/com/cloud/api/ApiServer.java @@ -119,6 +119,7 @@ import org.apache.cloudstack.framework.config.impl.ConfigurationVO; import org.apache.cloudstack.framework.jobs.AsyncJob; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.api.response.ApiResponseSerializer; import com.cloud.configuration.Config; @@ -183,11 +184,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer public ApiServer() { } - @PostConstruct - void initComponent() { - CallContext.init(_entityMgr); - } - @Override public boolean configure(String name, Map params) throws ConfigurationException { init(); @@ -976,7 +972,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } } - static class WorkerTask implements Runnable { + static class WorkerTask extends ManagedContextRunnable { private final HttpService _httpService; private final HttpServerConnection _conn; @@ -986,7 +982,7 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer } @Override - public void run() { + protected void runInContext() { HttpContext context = new BasicHttpContext(null); try { while (!Thread.interrupted() && _conn.isOpen()) { diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index 552327c83d1..def18d0919d 100755 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -34,11 +34,11 @@ import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; - import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.managed.context.ManagedContext; import com.cloud.exception.CloudAuthenticationException; import com.cloud.user.Account; @@ -57,6 +57,8 @@ public class ApiServlet extends HttpServlet { @Inject AccountService _accountMgr; @Inject EntityManager _entityMgr; + @Inject + ManagedContext _managedContext; public ApiServlet() { } @@ -105,8 +107,16 @@ public class ApiServlet extends HttpServlet { } } - @SuppressWarnings("unchecked") - private void processRequest(HttpServletRequest req, HttpServletResponse resp) { + private void processRequest(final HttpServletRequest req, final HttpServletResponse resp) { + _managedContext.runWithContext(new Runnable() { + @Override + public void run() { + processRequestInContext(req, resp); + } + }); + } + + private void processRequestInContext(HttpServletRequest req, HttpServletResponse resp) { StringBuffer auditTrailSb = new StringBuffer(); auditTrailSb.append(" " + req.getRemoteAddr()); auditTrailSb.append(" -- " + req.getMethod() + " "); diff --git a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 8cd44f44673..dcfb24c9d33 100644 --- a/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -22,7 +22,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Timer; -import java.util.TimerTask; import java.util.TreeSet; import javax.ejb.Local; @@ -43,6 +42,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageSubscriber; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; @@ -688,9 +688,9 @@ public class DeploymentPlanningManagerImpl extends ManagerBase implements Deploy return false; } - class HostReservationReleaseChecker extends TimerTask { + class HostReservationReleaseChecker extends ManagedContextTimerTask { @Override - public void run() { + protected void runInContext() { try { s_logger.debug("Checking if any host reservation can be released ... "); checkHostReservations(); diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerExtImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerExtImpl.java index f1e0f3f5dec..1107a7a031d 100644 --- a/server/src/com/cloud/ha/HighAvailabilityManagerExtImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerExtImpl.java @@ -26,8 +26,8 @@ import javax.naming.ConfigurationException; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.alert.AlertManager; import com.cloud.usage.dao.UsageJobDao; @@ -65,9 +65,9 @@ public class HighAvailabilityManagerExtImpl extends HighAvailabilityManagerImpl return true; } - protected class UsageServerMonitorTask implements Runnable { + protected class UsageServerMonitorTask extends ManagedContextRunnable{ @Override - public void run() { + protected void runInContext() { if (s_logger.isInfoEnabled()) { s_logger.info("checking health of usage server"); } diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index 464b9524556..59337c0326d 100755 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -31,10 +31,10 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.apache.log4j.NDC; - -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContext; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.agent.AgentManager; import com.cloud.alert.AlertManager; @@ -116,6 +116,9 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai @Inject ClusterDetailsDao _clusterDetailsDao; long _serverId; + + @Inject + ManagedContext _managedContext; List _investigators; public List getInvestigators() { @@ -773,9 +776,9 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai return true; } - protected class CleanupTask implements Runnable { + protected class CleanupTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { s_logger.info("HA Cleanup Thread Running"); try { @@ -793,71 +796,75 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai @Override public void run() { - ServerContexts.registerSystemContext(); - try { - s_logger.info("Starting work"); - while (!_stopped) { - HaWorkVO work = null; - try { - s_logger.trace("Checking the database"); - work = _haDao.take(_serverId); - if (work == null) { - try { - synchronized (this) { - wait(_timeToSleep); - } - continue; - } catch (final InterruptedException e) { - s_logger.info("Interrupted"); - continue; - } - } - - NDC.push("work-" + work.getId()); - s_logger.info("Processing " + work); - - try { - final WorkType wt = work.getWorkType(); - Long nextTime = null; - if (wt == WorkType.Migration) { - nextTime = migrate(work); - } else if (wt == WorkType.HA) { - nextTime = restart(work); - } else if (wt == WorkType.Stop || wt == WorkType.CheckStop || wt == WorkType.ForceStop) { - nextTime = stopVM(work); - } else if (wt == WorkType.Destroy) { - nextTime = destroyVM(work); - } else { - assert false : "How did we get here with " + wt.toString(); - continue; - } - - if (nextTime == null) { - s_logger.info("Completed " + work); - work.setStep(Step.Done); - } else { - s_logger.info("Rescheduling " + work + " to try again at " + new Date(nextTime << 10)); - work.setTimeToTry(nextTime); - work.setServerId(null); - work.setDateTaken(null); - } - } catch (Exception e) { - s_logger.error("Terminating " + work, e); - work.setStep(Step.Error); - } - _haDao.update(work.getId(), work); - } catch (final Throwable th) { - s_logger.error("Caught this throwable, ", th); - } finally { - if (work != null) { - NDC.pop(); - } - } + s_logger.info("Starting work"); + while (!_stopped) { + _managedContext.runWithContext(new Runnable() { + @Override + public void run() { + runWithContext(); } - s_logger.info("Time to go home!"); - } finally { - ServerContexts.unregisterSystemContext(); + }); } + s_logger.info("Time to go home!"); + } + + private void runWithContext() { + HaWorkVO work = null; + try { + s_logger.trace("Checking the database"); + work = _haDao.take(_serverId); + if (work == null) { + try { + synchronized (this) { + wait(_timeToSleep); + } + return; + } catch (final InterruptedException e) { + s_logger.info("Interrupted"); + return; + } + } + + NDC.push("work-" + work.getId()); + s_logger.info("Processing " + work); + + try { + final WorkType wt = work.getWorkType(); + Long nextTime = null; + if (wt == WorkType.Migration) { + nextTime = migrate(work); + } else if (wt == WorkType.HA) { + nextTime = restart(work); + } else if (wt == WorkType.Stop || wt == WorkType.CheckStop || wt == WorkType.ForceStop) { + nextTime = stopVM(work); + } else if (wt == WorkType.Destroy) { + nextTime = destroyVM(work); + } else { + assert false : "How did we get here with " + wt.toString(); + return; + } + + if (nextTime == null) { + s_logger.info("Completed " + work); + work.setStep(Step.Done); + } else { + s_logger.info("Rescheduling " + work + " to try again at " + new Date(nextTime << 10)); + work.setTimeToTry(nextTime); + work.setServerId(null); + work.setDateTaken(null); + } + } catch (Exception e) { + s_logger.error("Terminating " + work, e); + work.setStep(Step.Error); + } + _haDao.update(work.getId(), work); + } catch (final Throwable th) { + s_logger.error("Caught this throwable, ", th); + } finally { + if (work != null) { + NDC.pop(); + } + } } public synchronized void wakup() { diff --git a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java index f5c6eeca18d..00dd25c4a86 100644 --- a/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java +++ b/server/src/com/cloud/network/ExternalDeviceUsageManagerImpl.java @@ -31,8 +31,8 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.agent.AgentManager; import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer; @@ -331,14 +331,14 @@ public class ExternalDeviceUsageManagerImpl extends ManagerBase implements Exter } } - protected class ExternalDeviceNetworkUsageTask implements Runnable { + protected class ExternalDeviceNetworkUsageTask extends ManagedContextRunnable { public ExternalDeviceNetworkUsageTask() { } @Override - public void run() { + protected void runInContext() { GlobalLock scanLock = GlobalLock.getInternLock("ExternalDeviceNetworkUsageManagerImpl"); try { if (scanLock.lock(20)) { diff --git a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java index 1daa3f0dc1c..4794ee425ba 100644 --- a/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java +++ b/server/src/com/cloud/network/lb/LBHealthCheckManagerImpl.java @@ -29,8 +29,8 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.configuration.Config; import com.cloud.exception.ResourceUnavailableException; @@ -87,9 +87,9 @@ public class LBHealthCheckManagerImpl extends ManagerBase implements LBHealthChe return this.name; } - protected class UpdateLBHealthCheck implements Runnable { + protected class UpdateLBHealthCheck extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { updateLBHealthCheck(Scheme.Public); updateLBHealthCheck(Scheme.Internal); diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 043c376f558..5ea75604ebe 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -41,16 +41,15 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; +import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -852,14 +851,13 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } - protected class NetworkUsageTask implements Runnable { + protected class NetworkUsageTask extends ManagedContextRunnable { public NetworkUsageTask() { } @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { try{ final List routers = _routerDao.listByStateAndNetworkType(State.Running, GuestType.Isolated, mgmtSrvrId); s_logger.debug("Found " + routers.size() + " running routers. "); @@ -957,19 +955,17 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } catch (Exception e) { s_logger.warn("Error while collecting network stats", e); - } finally { - ServerContexts.unregisterSystemContext(); } } } - protected class NetworkStatsUpdateTask implements Runnable { + protected class NetworkStatsUpdateTask extends ManagedContextRunnable { public NetworkStatsUpdateTask() { } @Override - public void run() { + protected void runInContext() { GlobalLock scanLock = GlobalLock.getInternLock("network.stats"); try { if(scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { @@ -1201,7 +1197,7 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V return priority; } - protected class RvRStatusUpdateTask implements Runnable { + protected class RvRStatusUpdateTask extends ManagedContextRunnable { public RvRStatusUpdateTask() { } @@ -1280,60 +1276,54 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } @Override - public void run() { - ServerContexts.registerSystemContext(); - try { - while (true) { - try { - Long networkId = _vrUpdateQueue.take(); // This is a blocking call so this thread won't run all the time if no work item in queue. - List routers = _routerDao.listByNetworkAndRole(networkId, Role.VIRTUAL_ROUTER); - - if (routers.size() != 2) { - continue; - } - /* - * We update the router pair which the lower id router owned by this mgmt server, in order - * to prevent duplicate update of router status from cluster mgmt servers - */ - DomainRouterVO router0 = routers.get(0); - DomainRouterVO router1 = routers.get(1); - DomainRouterVO router = router0; - if ((router0.getId() < router1.getId()) && router0.getHostId() != null) { - router = router0; - } else { - router = router1; - } - if (router.getHostId() == null) { - s_logger.debug("Skip router pair (" + router0.getInstanceName() + "," + router1.getInstanceName() + ") due to can't find host"); - continue; - } - HostVO host = _hostDao.findById(router.getHostId()); - if (host == null || host.getManagementServerId() == null || - host.getManagementServerId() != ManagementServerNode.getManagementServerId()) { - s_logger.debug("Skip router pair (" + router0.getInstanceName() + "," + router1.getInstanceName() + ") due to not belong to this mgmt server"); - continue; - } - updateRoutersRedundantState(routers); - checkDuplicateMaster(routers); - checkSanity(routers); - } catch (Exception ex) { - s_logger.error("Fail to complete the RvRStatusUpdateTask! ", ex); - } + protected void runInContext() { + while (true) { + try { + Long networkId = _vrUpdateQueue.take(); // This is a blocking call so this thread won't run all the time if no work item in queue. + List routers = _routerDao.listByNetworkAndRole(networkId, Role.VIRTUAL_ROUTER); + + if (routers.size() != 2) { + continue; + } + /* + * We update the router pair which the lower id router owned by this mgmt server, in order + * to prevent duplicate update of router status from cluster mgmt servers + */ + DomainRouterVO router0 = routers.get(0); + DomainRouterVO router1 = routers.get(1); + DomainRouterVO router = router0; + if ((router0.getId() < router1.getId()) && router0.getHostId() != null) { + router = router0; + } else { + router = router1; + } + if (router.getHostId() == null) { + s_logger.debug("Skip router pair (" + router0.getInstanceName() + "," + router1.getInstanceName() + ") due to can't find host"); + continue; + } + HostVO host = _hostDao.findById(router.getHostId()); + if (host == null || host.getManagementServerId() == null || + host.getManagementServerId() != ManagementServerNode.getManagementServerId()) { + s_logger.debug("Skip router pair (" + router0.getInstanceName() + "," + router1.getInstanceName() + ") due to not belong to this mgmt server"); + continue; + } + updateRoutersRedundantState(routers); + checkDuplicateMaster(routers); + checkSanity(routers); + } catch (Exception ex) { + s_logger.error("Fail to complete the RvRStatusUpdateTask! ", ex); } - } finally { - ServerContexts.unregisterSystemContext(); } } } - protected class CheckRouterTask implements Runnable { + protected class CheckRouterTask extends ManagedContextRunnable { public CheckRouterTask() { } @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { try { final List routers = _routerDao.listIsolatedByHostId(null); s_logger.debug("Found " + routers.size() + " routers to update status. "); @@ -1350,8 +1340,6 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V } } catch (Exception ex) { s_logger.error("Fail to complete the CheckRouterTask! ", ex); - } finally { - ServerContexts.unregisterSystemContext(); } } } diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java index 18ee0f1124f..8b2db9dde90 100755 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl.java @@ -40,7 +40,6 @@ import javax.naming.ConfigurationException; import org.apache.commons.codec.digest.DigestUtils; import org.apache.log4j.Logger; - import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupEgressCmd; import org.apache.cloudstack.api.command.user.securitygroup.AuthorizeSecurityGroupIngressCmd; import org.apache.cloudstack.api.command.user.securitygroup.CreateSecurityGroupCmd; @@ -50,6 +49,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.RevokeSecurityGroupI import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.utils.identity.ManagementServerNode; import com.cloud.agent.AgentManager; @@ -187,9 +187,9 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } } - public class WorkerThread implements Runnable { + public class WorkerThread extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { Transaction txn = Transaction.open("SG Work"); try { @@ -210,9 +210,9 @@ public class SecurityGroupManagerImpl extends ManagerBase implements SecurityGro } } - public class CleanupThread implements Runnable { + public class CleanupThread extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { Transaction txn = Transaction.open("SG Cleanup"); try { diff --git a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java index a42881ec905..2fee7f312c8 100644 --- a/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java +++ b/server/src/com/cloud/network/security/SecurityGroupManagerImpl2.java @@ -25,8 +25,10 @@ import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import javax.ejb.Local; +import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.managed.context.ManagedContext; import org.springframework.context.annotation.Primary; import org.springframework.stereotype.Component; @@ -54,6 +56,9 @@ public class SecurityGroupManagerImpl2 extends SecurityGroupManagerImpl{ SecurityGroupWorkTracker _workTracker; SecurityManagerMBeanImpl _mBean; + @Inject + ManagedContext _managedContext; + WorkerThread[] _workers; private Set _disabledVms = Collections.newSetFromMap(new ConcurrentHashMap()); private boolean _schedulerDisabled = false; @@ -68,7 +73,12 @@ public class SecurityGroupManagerImpl2 extends SecurityGroupManagerImpl{ public void run() { while (true) { try{ - work(); + _managedContext.runWithContext(new Runnable() { + @Override + public void run() { + work(); + } + }); } catch (final Throwable th) { s_logger.error("SG Work: Caught this throwable, ", th); } diff --git a/server/src/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/com/cloud/network/vpc/VpcManagerImpl.java index 73b3aea66a2..651e82c6d21 100644 --- a/server/src/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/com/cloud/network/vpc/VpcManagerImpl.java @@ -31,8 +31,6 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.log4j.Logger; - import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.api.command.user.vpc.ListPrivateGatewaysCmd; import org.apache.cloudstack.api.command.user.vpc.ListStaticRoutesCmd; @@ -40,6 +38,8 @@ import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.ConfigDepot; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.log4j.Logger; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -1932,9 +1932,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - protected class VpcCleanupTask implements Runnable { + protected class VpcCleanupTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { GlobalLock lock = GlobalLock.getInternLock("VpcCleanup"); if (lock == null) { diff --git a/server/src/com/cloud/projects/ProjectManagerImpl.java b/server/src/com/cloud/projects/ProjectManagerImpl.java index edcdf3f1a2b..a385739f9aa 100755 --- a/server/src/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/com/cloud/projects/ProjectManagerImpl.java @@ -42,7 +42,7 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; - +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -83,7 +83,6 @@ import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.DB; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; - import com.sun.mail.smtp.SMTPMessage; import com.sun.mail.smtp.SMTPSSLTransport; import com.sun.mail.smtp.SMTPTransport; @@ -1003,9 +1002,9 @@ public class ProjectManagerImpl extends ManagerBase implements ProjectManager { } } - public class ExpiredInvitationsCleanup implements Runnable { + public class ExpiredInvitationsCleanup extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { TimeZone.getDefault(); List invitationsToExpire = _projectInvitationDao.listInvitationsToExpire(_invitationTimeOut); diff --git a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java index 376e943393b..1f8713aae76 100755 --- a/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java +++ b/server/src/com/cloud/resourcelimit/ResourceLimitManagerImpl.java @@ -32,9 +32,9 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; - import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -939,13 +939,13 @@ public class ResourceLimitManagerImpl extends ManagerBase implements ResourceLim return _resourceCountDao.getResourceCount(account.getId(), ResourceOwnerType.Account, type); } - protected class ResourceCountCheckTask implements Runnable { + protected class ResourceCountCheckTask extends ManagedContextRunnable { public ResourceCountCheckTask() { } @Override - public void run() { + protected void runInContext() { s_logger.info("Running resource count check periodic task"); List domains = _domainDao.findImmediateChildrenForParent(DomainVO.ROOT_DOMAIN); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 1c316103424..0a0fcdc08c3 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -432,6 +432,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -2862,9 +2863,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe return cmdList; } - protected class EventPurgeTask implements Runnable { + protected class EventPurgeTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { GlobalLock lock = GlobalLock.getInternLock("EventPurge"); if (lock == null) { @@ -2896,9 +2897,9 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } } - protected class AlertPurgeTask implements Runnable { + protected class AlertPurgeTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { GlobalLock lock = GlobalLock.getInternLock("AlertPurge"); if (lock == null) { diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index 5e110aa53d5..b4ec9155faf 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -37,6 +37,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; @@ -230,9 +231,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } - class HostCollector implements Runnable { + class HostCollector extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { s_logger.debug("HostStatsCollector is running..."); @@ -273,9 +274,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } } - class VmStatsCollector implements Runnable { + class VmStatsCollector extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { s_logger.debug("VmStatsCollector is running..."); @@ -350,9 +351,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc return _VmStats.get(id); } - class VmDiskStatsUpdaterTask implements Runnable { + class VmDiskStatsUpdaterTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { GlobalLock scanLock = GlobalLock.getInternLock("vm.disk.stats"); try { if(scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { @@ -397,9 +398,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } } - class VmDiskStatsTask implements Runnable { + class VmDiskStatsTask extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { // collect the vm disk statistics(total) from hypervisor. added by weizhou, 2013.03. Transaction txn = Transaction.open(Transaction.CLOUD_DB); try { @@ -520,9 +521,9 @@ public class StatsCollector extends ManagerBase implements ComponentMethodInterc } } - class StorageCollector implements Runnable { + class StorageCollector extends ManagedContextRunnable { @Override - public void run() { + protected void runInContext() { try { if (s_logger.isDebugEnabled()) { s_logger.debug("StorageCollector is running..."); diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 415111d4c91..c046057db51 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -43,7 +43,6 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd; import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd; import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd; @@ -74,6 +73,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeAp import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreDetailsDao; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; @@ -1243,13 +1243,13 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(primaryStorage.getId(), DataStoreRole.Primary); } - protected class StorageGarbageCollector implements Runnable { + protected class StorageGarbageCollector extends ManagedContextRunnable { public StorageGarbageCollector() { } @Override - public void run() { + protected void runInContext() { try { s_logger.trace("Storage Garbage Collection Thread is running."); diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index e5efcb2bbd7..91ae0ae786a 100755 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -27,7 +27,6 @@ import javax.inject.Inject; import org.apache.log4j.Level; import org.apache.log4j.Logger; - import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; @@ -36,6 +35,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.TemplateService; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.cloudstack.storage.command.DownloadCommand; import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType; import org.apache.cloudstack.storage.command.DownloadProgressCommand; @@ -68,7 +68,7 @@ import com.cloud.utils.exception.CloudRuntimeException; public class DownloadListener implements Listener { - private static final class StatusTask extends TimerTask { + private static final class StatusTask extends ManagedContextTimerTask { private final DownloadListener dl; private final RequestType reqType; @@ -78,13 +78,13 @@ public class DownloadListener implements Listener { } @Override - public void run() { + protected void runInContext() { dl.sendCommand(reqType); } } - private static final class TimeoutTask extends TimerTask { + private static final class TimeoutTask extends ManagedContextTimerTask { private final DownloadListener dl; public TimeoutTask( DownloadListener dl) { @@ -92,7 +92,7 @@ public class DownloadListener implements Listener { } @Override - public void run() { + protected void runInContext() { dl.checkProgress(); } } diff --git a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java index 52e20f02c08..15e9cd3438a 100644 --- a/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotSchedulerImpl.java @@ -33,11 +33,11 @@ import org.springframework.stereotype.Component; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotCmd; -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.framework.jobs.dao.AsyncJobDao; import org.apache.cloudstack.framework.jobs.impl.AsyncJobVO; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import com.cloud.api.ApiDispatcher; import com.cloud.api.ApiGsonHelper; @@ -371,17 +371,14 @@ public class SnapshotSchedulerImpl extends ManagerBase implements SnapshotSchedu _testClockTimer.schedule(_testTimerTask, 100*1000L, 60*1000L); } else { - TimerTask timerTask = new TimerTask() { + TimerTask timerTask = new ManagedContextTimerTask() { @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { try { Date currentTimestamp = new Date(); poll(currentTimestamp); } catch (Throwable t) { s_logger.warn("Catch throwable in snapshot scheduler ", t); - } finally { - ServerContexts.unregisterSystemContext(); } } }; diff --git a/server/src/com/cloud/storage/upload/UploadListener.java b/server/src/com/cloud/storage/upload/UploadListener.java index 09db421617f..add58774c28 100755 --- a/server/src/com/cloud/storage/upload/UploadListener.java +++ b/server/src/com/cloud/storage/upload/UploadListener.java @@ -27,7 +27,6 @@ import javax.inject.Inject; import org.apache.log4j.Level; import org.apache.log4j.Logger; - import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd; @@ -38,6 +37,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.jobs.AsyncJobManager; import org.apache.cloudstack.jobs.JobInfo; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import com.cloud.agent.Listener; import com.cloud.agent.api.AgentControlAnswer; @@ -63,7 +63,7 @@ import com.cloud.utils.exception.CloudRuntimeException; public class UploadListener implements Listener { - private static final class StatusTask extends TimerTask { + private static final class StatusTask extends ManagedContextTimerTask { private final UploadListener ul; private final RequestType reqType; @@ -73,13 +73,13 @@ public class UploadListener implements Listener { } @Override - public void run() { + protected void runInContext() { ul.sendCommand(reqType); } } - private static final class TimeoutTask extends TimerTask { + private static final class TimeoutTask extends ManagedContextTimerTask { private final UploadListener ul; public TimeoutTask(UploadListener ul) { @@ -87,7 +87,7 @@ public class UploadListener implements Listener { } @Override - public void run() { + protected void runInContext() { ul.checkProgress(); } } diff --git a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java index 12378de870d..4eb4900e67d 100755 --- a/server/src/com/cloud/storage/upload/UploadMonitorImpl.java +++ b/server/src/com/cloud/storage/upload/UploadMonitorImpl.java @@ -34,13 +34,13 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; - import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity; @@ -441,13 +441,13 @@ public class UploadMonitorImpl extends ManagerBase implements UploadMonitor { } - protected class StorageGarbageCollector implements Runnable { + protected class StorageGarbageCollector extends ManagedContextRunnable { public StorageGarbageCollector() { } @Override - public void run() { + protected void runInContext() { try { GlobalLock scanLock = GlobalLock.getInternLock("uploadmonitor.storageGC"); try { diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index 5240102a879..c1ce89205ad 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -73,6 +73,7 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.command.AttachCommand; import org.apache.cloudstack.storage.command.CommandResult; import org.apache.cloudstack.storage.command.DettachCommand; @@ -488,9 +489,9 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, for (final StoragePoolVO pool : pools) { if (pool.getDataCenterId() == zoneId) { s_logger.info("Schedule to preload template " + template.getId() + " into primary storage " + pool.getId()); - _preloadExecutor.execute(new Runnable() { + _preloadExecutor.execute(new ManagedContextRunnable() { @Override - public void run() { + protected void runInContext() { try { reallyRun(); } catch (Throwable e) { diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 396319af538..ae93548b7e2 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -50,9 +50,9 @@ import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd; import org.apache.cloudstack.api.command.admin.user.RegisterCmd; import org.apache.cloudstack.api.command.admin.user.UpdateUserCmd; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.region.gslb.GlobalLoadBalancerRuleDao; import com.cloud.api.ApiDBUtils; @@ -1492,18 +1492,10 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M return _userDao.remove(id); } - public class ResourceCountCalculateTask implements Runnable { + protected class AccountCleanupTask extends ManagedContextRunnable { @Override - public void run() { - - } - } - - protected class AccountCleanupTask implements Runnable { - @Override - public void run() { + protected void runInContext() { try { - ServerContexts.registerSystemContext(); GlobalLock lock = GlobalLock.getInternLock("AccountCleanup"); if (lock == null) { s_logger.debug("Couldn't get the global lock"); @@ -1585,7 +1577,6 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M s_logger.error("Exception ", e); } finally { lock.unlock(); - ServerContexts.unregisterSystemContext(); } } catch (Exception e) { s_logger.error("Exception ", e); diff --git a/server/src/com/cloud/vm/SystemVmLoadScanner.java b/server/src/com/cloud/vm/SystemVmLoadScanner.java index 3932c3b9641..6e5521632c2 100644 --- a/server/src/com/cloud/vm/SystemVmLoadScanner.java +++ b/server/src/com/cloud/vm/SystemVmLoadScanner.java @@ -21,8 +21,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; - -import org.apache.cloudstack.context.ServerContexts; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import com.cloud.utils.Pair; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -64,17 +63,14 @@ public class SystemVmLoadScanner { } private Runnable getCapacityScanTask() { - return new Runnable() { + return new ManagedContextRunnable() { @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { try { reallyRun(); } catch (Throwable e) { s_logger.warn("Unexpected exception " + e.getMessage(), e); - } finally { - ServerContexts.unregisterSystemContext(); } } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index 55d166ce1a9..6e879161276 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -61,7 +61,6 @@ import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.context.ServerContexts; import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; @@ -72,6 +71,7 @@ import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.jobs.AsyncJobManager; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.TemplateObjectTO; @@ -1708,13 +1708,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } - protected class ExpungeTask implements Runnable { + protected class ExpungeTask extends ManagedContextRunnable { public ExpungeTask() { } @Override - public void run() { - ServerContexts.registerSystemContext(); + protected void runInContext() { GlobalLock scanLock = GlobalLock.getInternLock("UserVMExpunge"); try { if (scanLock.lock(ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION)) { @@ -1748,7 +1747,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } } finally { scanLock.releaseRef(); - ServerContexts.unregisterSystemContext(); } } diff --git a/usage/src/com/cloud/usage/UsageManagerImpl.java b/usage/src/com/cloud/usage/UsageManagerImpl.java index 90ce4db7635..5f2867450ae 100644 --- a/usage/src/com/cloud/usage/UsageManagerImpl.java +++ b/usage/src/com/cloud/usage/UsageManagerImpl.java @@ -35,10 +35,10 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.log4j.Logger; - import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.managed.context.ManagedContext; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.cloudstack.usage.UsageTypes; - import org.springframework.stereotype.Component; import com.cloud.alert.AlertManager; @@ -279,7 +279,17 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna return true; } + @Override public void run() { + new ManagedContextRunnable() { + @Override + protected void runInContext() { + runInContext(); + } + }; + } + + protected void runInContext() { if (s_logger.isInfoEnabled()) { s_logger.info("starting usage job..."); } @@ -1651,8 +1661,9 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna m_usageVMSnapshotDao.persist(vsVO); } - private class Heartbeat implements Runnable { - public void run() { + private class Heartbeat extends ManagedContextRunnable { + @Override + protected void runInContext() { Transaction usageTxn = Transaction.open(Transaction.USAGE_DB); try { if(!m_heartbeatLock.lock(3)) { // 3 second timeout @@ -1757,8 +1768,9 @@ public class UsageManagerImpl extends ManagerBase implements UsageManager, Runna } } - private class SanityCheck implements Runnable { - public void run() { + private class SanityCheck extends ManagedContextRunnable { + @Override + protected void runInContext() { UsageSanityChecker usc = new UsageSanityChecker(); try { String errors = usc.runSanityCheck(); diff --git a/usage/src/com/cloud/usage/parser/UsageParser.java b/usage/src/com/cloud/usage/parser/UsageParser.java index 410e876fd1c..80437d579a0 100644 --- a/usage/src/com/cloud/usage/parser/UsageParser.java +++ b/usage/src/com/cloud/usage/parser/UsageParser.java @@ -18,12 +18,13 @@ package com.cloud.usage.parser; import java.util.Date; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; import org.apache.log4j.Logger; -public abstract class UsageParser implements Runnable { +public abstract class UsageParser extends ManagedContextRunnable { public static final Logger s_logger = Logger.getLogger(UsageParser.class.getName()); - public void run() { + protected void runInContext() { try { parse(null); } catch (Exception e) { diff --git a/utils/pom.xml b/utils/pom.xml index 09c960258a6..35012b23343 100644 --- a/utils/pom.xml +++ b/utils/pom.xml @@ -26,7 +26,12 @@ 4.3.0-SNAPSHOT ../pom.xml - + + + org.apache.cloudstack + cloud-framework-managed-context + ${project.version} + org.springframework spring-context @@ -35,6 +40,14 @@ log4j log4j + + org.slf4j + slf4j-api + + + org.slf4j + slf4j-log4j12 + cglib cglib-nodep diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java index 18af7cd2338..c36b3a8ce24 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareContextPool.java @@ -23,6 +23,8 @@ import java.util.Map; import java.util.Timer; import java.util.TimerTask; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; import org.apache.log4j.Logger; public class VmwareContextPool { @@ -117,9 +119,9 @@ public class VmwareContextPool { } private TimerTask getTimerTask() { - return new TimerTask() { - @Override - public void run() { + return new ManagedContextTimerTask() { + @Override + protected void runInContext() { try { // doIdleCheck();