You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2021/02/01 16:56:37 UTC
[tomcat] branch serviced created (now ee60693)
This is an automated email from the ASF dual-hosted git repository.
markt pushed a change to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git.
at ee60693 Allow Manager app to deploy applications in parallel
This branch includes the following new commits:
new 2a7521a Refactor tracking of serviced applications to use a concurrent Set
new c662de6 Switch to the thread-safe method of serviced application tracking
new 79e00bd Avoid servicing conflicts between MBeanFactory and other channels
new 646224b Refactor HostConfig to track serviced apps consistently
new 3da1d7e Deprecated isServiced as unused
new 5102524 Refactor marking app as serviced when using check
new ee60693 Allow Manager app to deploy applications in parallel
The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 04/07: Refactor HostConfig to track serviced apps
consistently
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 646224b9b394294a56f3d8056b7f1c717be07d11
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Thu Jan 21 10:08:49 2021 +0000
Refactor HostConfig to track serviced apps consistently
Fourth in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
Rather than just call isServiced() which only checks if another component
is working with the app at that point in time, call tryAddServiced which
also prevents other components from working with the app while the
deployer is working.
Review the code to ensure that there is only one call to tryAddServiced
on each code path that services an app (a second call would fail) and
that the necessary removeServiced calls are present in catch and/or
finally blocks as appropriate.
---
java/org/apache/catalina/startup/HostConfig.java | 199 +++++++++++++++--------
1 file changed, 132 insertions(+), 67 deletions(-)
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 3ffc360..5e7ea52 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -510,6 +510,10 @@ public class HostConfig implements LifecycleListener {
/**
* Deploy applications for any directories or WAR files that are found
* in our "application root" directory.
+ * <p>
+ * Note: It is expected that the caller has successfully added the app
+ * to servicedSet before calling this method.
+ *
* @param name The context name which should be deployed
*/
protected void deployApps(String name) {
@@ -563,11 +567,21 @@ public class HostConfig implements LifecycleListener {
if (file.toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
ContextName cn = new ContextName(file, true);
- if (isServiced(cn.getName()) || deploymentExists(cn.getName())) {
- continue;
- }
+ if (tryAddServiced(cn.getName())) {
+ try {
+ if (deploymentExists(cn.getName())) {
+ removeServiced(cn.getName());
+ continue;
+ }
- results.add(es.submit(new DeployDescriptor(this, cn, contextXml)));
+ // DeployDescriptor will call removeServiced
+ results.add(es.submit(new DeployDescriptor(this, cn, contextXml)));
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ removeServiced(cn.getName());
+ throw t;
+ }
+ }
}
}
@@ -583,6 +597,10 @@ public class HostConfig implements LifecycleListener {
/**
* Deploy specified context descriptor.
+ * <p>
+ * Note: It is expected that the caller has successfully added the app
+ * to servicedSet before calling this method.
+ *
* @param cn The context name
* @param contextXml The descriptor
*/
@@ -764,41 +782,48 @@ public class HostConfig implements LifecycleListener {
File war = new File(appBase, file);
if (file.toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() && !invalidWars.contains(file)) {
ContextName cn = new ContextName(file, true);
-
- if (isServiced(cn.getName())) {
- continue;
- }
- if (deploymentExists(cn.getName())) {
- DeployedApplication app = deployed.get(cn.getName());
- boolean unpackWAR = unpackWARs;
- if (unpackWAR && host.findChild(cn.getName()) instanceof StandardContext) {
- unpackWAR = ((StandardContext) host.findChild(cn.getName())).getUnpackWAR();
- }
- if (!unpackWAR && app != null) {
- // Need to check for a directory that should not be
- // there
- File dir = new File(appBase, cn.getBaseName());
- if (dir.exists()) {
- if (!app.loggedDirWarning) {
- log.warn(sm.getString("hostConfig.deployWar.hiddenDir",
- dir.getAbsoluteFile(), war.getAbsoluteFile()));
- app.loggedDirWarning = true;
+ if (tryAddServiced(cn.getName())) {
+ try {
+ if (deploymentExists(cn.getName())) {
+ DeployedApplication app = deployed.get(cn.getName());
+ boolean unpackWAR = unpackWARs;
+ if (unpackWAR && host.findChild(cn.getName()) instanceof StandardContext) {
+ unpackWAR = ((StandardContext) host.findChild(cn.getName())).getUnpackWAR();
}
- } else {
- app.loggedDirWarning = false;
+ if (!unpackWAR && app != null) {
+ // Need to check for a directory that should not be
+ // there
+ File dir = new File(appBase, cn.getBaseName());
+ if (dir.exists()) {
+ if (!app.loggedDirWarning) {
+ log.warn(sm.getString("hostConfig.deployWar.hiddenDir",
+ dir.getAbsoluteFile(), war.getAbsoluteFile()));
+ app.loggedDirWarning = true;
+ }
+ } else {
+ app.loggedDirWarning = false;
+ }
+ }
+ removeServiced(cn.getName());
+ continue;
}
- }
- continue;
- }
- // Check for WARs with /../ /./ or similar sequences in the name
- if (!validateContextPath(appBase, cn.getBaseName())) {
- log.error(sm.getString("hostConfig.illegalWarName", file));
- invalidWars.add(file);
- continue;
- }
+ // Check for WARs with /../ /./ or similar sequences in the name
+ if (!validateContextPath(appBase, cn.getBaseName())) {
+ log.error(sm.getString("hostConfig.illegalWarName", file));
+ invalidWars.add(file);
+ removeServiced(cn.getName());
+ continue;
+ }
- results.add(es.submit(new DeployWar(this, cn, war)));
+ // DeployWAR will call removeServiced
+ results.add(es.submit(new DeployWar(this, cn, war)));
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ removeServiced(cn.getName());
+ throw t;
+ }
+ }
}
}
@@ -848,6 +873,10 @@ public class HostConfig implements LifecycleListener {
/**
* Deploy packed WAR.
+ * <p>
+ * Note: It is expected that the caller has successfully added the app
+ * to servicedSet before calling this method.
+ *
* @param cn The context name
* @param war The WAR file
*/
@@ -1050,11 +1079,21 @@ public class HostConfig implements LifecycleListener {
if (dir.isDirectory()) {
ContextName cn = new ContextName(file, false);
- if (isServiced(cn.getName()) || deploymentExists(cn.getName())) {
- continue;
- }
+ if (tryAddServiced(cn.getName())) {
+ try {
+ if (deploymentExists(cn.getName())) {
+ removeServiced(cn.getName());
+ continue;
+ }
- results.add(es.submit(new DeployDirectory(this, cn, dir)));
+ // DeployDirectory will call removeServiced
+ results.add(es.submit(new DeployDirectory(this, cn, dir)));
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ removeServiced(cn.getName());
+ throw t;
+ }
+ }
}
}
@@ -1070,6 +1109,10 @@ public class HostConfig implements LifecycleListener {
/**
* Deploy exploded webapp.
+ * <p>
+ * Note: It is expected that the caller has successfully added the app
+ * to servicedSet before calling this method.
+ *
* @param cn The context name
* @param dir The path to the root folder of the weapp
*/
@@ -1595,8 +1638,12 @@ public class HostConfig implements LifecycleListener {
// Check for resources modification to trigger redeployment
DeployedApplication[] apps = deployed.values().toArray(new DeployedApplication[0]);
for (DeployedApplication app : apps) {
- if (!isServiced(app.name)) {
- checkResources(app, false);
+ if (tryAddServiced(app.name)) {
+ try {
+ checkResources(app, false);
+ } finally {
+ removeServiced(app.name);
+ }
}
}
@@ -1656,27 +1703,31 @@ public class HostConfig implements LifecycleListener {
Context currentContext = (Context) host.findChild(current.getName());
if (previousContext != null && currentContext != null &&
currentContext.getState().isAvailable() &&
- !isServiced(previous.getName())) {
- Manager manager = previousContext.getManager();
- if (manager != null) {
- int sessionCount;
- if (manager instanceof DistributedManager) {
- sessionCount = ((DistributedManager) manager).getActiveSessionsFull();
- } else {
- sessionCount = manager.getActiveSessions();
- }
- if (sessionCount == 0) {
- if (log.isInfoEnabled()) {
- log.info(sm.getString("hostConfig.undeployVersion", previous.getName()));
+ tryAddServiced(previous.getName())) {
+ try {
+ Manager manager = previousContext.getManager();
+ if (manager != null) {
+ int sessionCount;
+ if (manager instanceof DistributedManager) {
+ sessionCount = ((DistributedManager) manager).getActiveSessionsFull();
+ } else {
+ sessionCount = manager.getActiveSessions();
+ }
+ if (sessionCount == 0) {
+ if (log.isInfoEnabled()) {
+ log.info(sm.getString("hostConfig.undeployVersion", previous.getName()));
+ }
+ DeployedApplication app = deployed.get(previous.getName());
+ String[] resources = app.redeployResources.keySet().toArray(new String[0]);
+ // Version is unused - undeploy it completely
+ // The -1 is a 'trick' to ensure all redeploy
+ // resources are removed
+ undeploy(app);
+ deleteRedeployResources(app, resources, -1, true);
}
- DeployedApplication app = deployed.get(previous.getName());
- String[] resources = app.redeployResources.keySet().toArray(new String[0]);
- // Version is unused - undeploy it completely
- // The -1 is a 'trick' to ensure all redeploy
- // resources are removed
- undeploy(app);
- deleteRedeployResources(app, resources, -1, true);
}
+ } finally {
+ removeServiced(previous.getName());
}
}
}
@@ -1733,13 +1784,15 @@ public class HostConfig implements LifecycleListener {
/**
* Remove a webapp from our control.
* Entry point for the admin webapp, and other JMX Context controllers.
+ * <p>
+ * Note: It is expected that the caller has successfully added the app
+ * to servicedSet before calling this method.
+ *
* @param contextName The context name
*/
public void unmanageApp(String contextName) {
- if(isServiced(contextName)) {
- deployed.remove(contextName);
- host.removeChild(host.findChild(contextName));
- }
+ deployed.remove(contextName);
+ host.removeChild(host.findChild(contextName));
}
// ----------------------------------------------------- Instance Variables
@@ -1815,7 +1868,11 @@ public class HostConfig implements LifecycleListener {
@Override
public void run() {
- config.deployDescriptor(cn, descriptor);
+ try {
+ config.deployDescriptor(cn, descriptor);
+ } finally {
+ config.removeServiced(cn.getName());
+ }
}
}
@@ -1833,7 +1890,11 @@ public class HostConfig implements LifecycleListener {
@Override
public void run() {
- config.deployWAR(cn, war);
+ try {
+ config.deployWAR(cn, war);
+ } finally {
+ config.removeServiced(cn.getName());
+ }
}
}
@@ -1851,7 +1912,11 @@ public class HostConfig implements LifecycleListener {
@Override
public void run() {
- config.deployDirectory(cn, dir);
+ try {
+ config.deployDirectory(cn, dir);
+ } finally {
+ config.removeServiced(cn.getName());
+ }
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 03/07: Avoid servicing conflicts between MBeanFactory and
other channels
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 79e00bdcb5bbabc39d73730c7948a2cb7d358c4f
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Jan 20 19:35:10 2021 +0000
Avoid servicing conflicts between MBeanFactory and other channels
Third in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
Prior to this patch MBeanFactory did not check whether the app to be
deployed was already listed as being serviced. This is now checked
(using the new thread safe tryAddServiced) before trying to add or
remove an app via MBeanFactory
---
.../apache/catalina/mbeans/LocalStrings.properties | 2 +
java/org/apache/catalina/mbeans/MBeanFactory.java | 61 +++++++++++++---------
2 files changed, 39 insertions(+), 24 deletions(-)
diff --git a/java/org/apache/catalina/mbeans/LocalStrings.properties b/java/org/apache/catalina/mbeans/LocalStrings.properties
index b139f3d..0063c37 100644
--- a/java/org/apache/catalina/mbeans/LocalStrings.properties
+++ b/java/org/apache/catalina/mbeans/LocalStrings.properties
@@ -29,7 +29,9 @@ mBean.nullName=Attribute name is null
mBeanDumper.getAttributeError=Error getting attribute [{0}] for object name [{1}]
+mBeanFactory.contextCreate.addServicedFail=Unable to create context [{0}] as another component is currently servicing a context with that name
mBeanFactory.contextDestroyError=Error during context [{0}] destroy
+mBeanFactory.contextRemove.addServicedFail=Unable to remove context [{0}] as another component is currently servicing that context
mBeanFactory.managerContext=Manager components may only be added to Contexts.
mBeanFactory.noDeployer=Deployer not found for host [{0}]
mBeanFactory.noService=Service with the domain [{0}] was not found
diff --git a/java/org/apache/catalina/mbeans/MBeanFactory.java b/java/org/apache/catalina/mbeans/MBeanFactory.java
index 2858615..ea963d1 100644
--- a/java/org/apache/catalina/mbeans/MBeanFactory.java
+++ b/java/org/apache/catalina/mbeans/MBeanFactory.java
@@ -414,22 +414,28 @@ public class MBeanFactory {
pname.getKeyProperty("host"));
if(mserver.isRegistered(deployer)) {
String contextName = context.getName();
- mserver.invoke(deployer, "addServiced",
- new Object [] {contextName},
- new String [] {"java.lang.String"});
- String configPath = (String)mserver.getAttribute(deployer,
- "configBaseName");
- String baseName = context.getBaseName();
- File configFile = new File(new File(configPath), baseName+".xml");
- if (configFile.isFile()) {
- context.setConfigFile(configFile.toURI().toURL());
+ Boolean result = (Boolean) mserver.invoke(deployer, "tryAddServiced",
+ new Object [] {contextName},
+ new String [] {"java.lang.String"});
+ if (result.booleanValue()) {
+ try {
+ String configPath = (String)mserver.getAttribute(deployer, "configBaseName");
+ String baseName = context.getBaseName();
+ File configFile = new File(new File(configPath), baseName+".xml");
+ if (configFile.isFile()) {
+ context.setConfigFile(configFile.toURI().toURL());
+ }
+ mserver.invoke(deployer, "manageApp",
+ new Object[] {context},
+ new String[] {"org.apache.catalina.Context"});
+ } finally {
+ mserver.invoke(deployer, "removeServiced",
+ new Object [] {contextName},
+ new String [] {"java.lang.String"});
+ }
+ } else {
+ throw new IllegalStateException(sm.getString("mBeanFactory.contextRemove.addServicedFail", contextName));
}
- mserver.invoke(deployer, "manageApp",
- new Object[] {context},
- new String[] {"org.apache.catalina.Context"});
- mserver.invoke(deployer, "removeServiced",
- new Object [] {contextName},
- new String [] {"java.lang.String"});
} else {
log.warn(sm.getString("mBeanFactory.noDeployer", pname.getKeyProperty("host")));
Service service = getService(pname);
@@ -712,15 +718,22 @@ public class MBeanFactory {
hostName);
String pathStr = getPathStr(path);
if(mserver.isRegistered(deployer)) {
- mserver.invoke(deployer,"addServiced",
- new Object[]{pathStr},
- new String[] {"java.lang.String"});
- mserver.invoke(deployer,"unmanageApp",
- new Object[] {pathStr},
- new String[] {"java.lang.String"});
- mserver.invoke(deployer,"removeServiced",
- new Object[] {pathStr},
- new String[] {"java.lang.String"});
+ Boolean result = (Boolean) mserver.invoke(deployer,"tryAddServiced",
+ new Object[]{pathStr},
+ new String[] {"java.lang.String"});
+ if (result.booleanValue()) {
+ try {
+ mserver.invoke(deployer,"unmanageApp",
+ new Object[] {pathStr},
+ new String[] {"java.lang.String"});
+ } finally {
+ mserver.invoke(deployer,"removeServiced",
+ new Object[] {pathStr},
+ new String[] {"java.lang.String"});
+ }
+ } else {
+ throw new IllegalStateException(sm.getString("mBeanFactory.removeCreate.addServicedFail", pathStr));
+ }
} else {
log.warn(sm.getString("mBeanFactory.noDeployer", hostName));
Host host = (Host) engine.findChild(hostName);
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 06/07: Refactor marking app as serviced when using check
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 510252485501b31f1ead459bb81f9abda9477c02
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Jan 22 19:52:04 2021 +0000
Refactor marking app as serviced when using check
Sixth in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
Check triggers HostConfig to redploy the application if it has been
updated. check calls tryAddServiced to avoid conflicts so existing
calls to check can't be made from inside a tryAddServiced ...
removeServiced block.
---
java/org/apache/catalina/ha/deploy/FarmWarDeployer.java | 8 +++-----
java/org/apache/catalina/manager/HTMLManagerServlet.java | 4 ++--
java/org/apache/catalina/manager/ManagerServlet.java | 16 ++++++++--------
java/org/apache/catalina/startup/HostConfig.java | 15 ++++++++++-----
4 files changed, 23 insertions(+), 20 deletions(-)
diff --git a/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java b/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
index 09f075b..4912b7f 100644
--- a/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
+++ b/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
@@ -236,10 +236,10 @@ public class FarmWarDeployer extends ClusterListener
"farmWarDeployer.renameFail",
factory.getFile(), deployable));
}
- check(contextName);
} finally {
removeServiced(contextName);
}
+ check(contextName);
if (log.isDebugEnabled())
log.debug(sm.getString(
"farmWarDeployer.deployEnd",
@@ -424,6 +424,7 @@ public class FarmWarDeployer extends ClusterListener
} finally {
removeServiced(contextName);
}
+ check(contextName);
} else
log.error(sm.getString("farmWarDeployer.removeFailRemote",
contextName));
@@ -458,10 +459,10 @@ public class FarmWarDeployer extends ClusterListener
if (tryAddServiced(cn.getName())) {
try {
copy(newWar, deployWar);
- check(cn.getName());
} finally {
removeServiced(cn.getName());
}
+ check(cn.getName());
} else {
log.error(sm.getString("farmWarDeployer.servicingDeploy",
cn.getName(), deployWar.getName()));
@@ -519,10 +520,7 @@ public class FarmWarDeployer extends ClusterListener
log.error(sm.getString("farmWarDeployer.deleteFail", xml));
}
}
- // Perform new deployment and remove internal HostConfig state
- check(contextName);
}
-
}
/**
diff --git a/java/org/apache/catalina/manager/HTMLManagerServlet.java b/java/org/apache/catalina/manager/HTMLManagerServlet.java
index 65601ec..0db12ef 100644
--- a/java/org/apache/catalina/manager/HTMLManagerServlet.java
+++ b/java/org/apache/catalina/manager/HTMLManagerServlet.java
@@ -287,11 +287,11 @@ public final class HTMLManagerServlet extends ManagerServlet {
if (tryAddServiced(name)) {
try {
warPart.write(file.getAbsolutePath());
- // Perform new deployment
- check(name);
} finally {
removeServiced(name);
}
+ // Perform new deployment
+ check(name);
} else {
message = smClient.getString("managerServlet.inService", name);
}
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index dd68e1b..8f4b825 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -846,11 +846,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
// Copy WAR to the host's appBase
ExpandWar.copy(uploadedWar, deployedWar);
}
- // Perform new deployment
- check(name);
} finally {
removeServiced(name);
}
+ // Perform new deployment
+ check(name);
} else {
writer.println(smClient.getString("managerServlet.inService", displayPath));
}
@@ -903,11 +903,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
return;
}
ExpandWar.copy(localWar, deployedWar);
- // Perform new deployment
- check(name);
} finally {
removeServiced(name);
}
+ // Perform new deployment
+ check(name);
} else {
writer.println(smClient.getString("managerServlet.inService", displayPath));
}
@@ -1017,11 +1017,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
}
ExpandWar.copy(new File(war), localWar);
}
- // Perform new deployment
- check(name);
} finally {
removeServiced(name);
}
+ // Perform new deployment
+ check(name);
} else {
writer.println(smClient.getString("managerServlet.inService", displayPath));
}
@@ -1519,11 +1519,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
"managerServlet.deleteFail", xml));
return;
}
- // Perform new deployment
- check(name);
} finally {
removeServiced(name);
}
+ // Perform new deployment
+ check(name);
} else {
writer.println(smClient.getString("managerServlet.inService", displayPath));
}
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 2853199..2079117 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -1667,17 +1667,22 @@ public class HostConfig implements LifecycleListener {
* it as necessary. This method is for use with functionality such as
* management web applications that upload new/updated web applications and
* need to trigger the appropriate action to deploy them. This method
- * assumes that the web application is currently marked as serviced and that
- * any uploading/updating has been completed before this method is called.
- * Any action taken as a result of the checks will complete before this
- * method returns.
+ * assumes that any uploading/updating has been completed before this method
+ * is called. Any action taken as a result of the checks will complete
+ * before this method returns.
*
* @param name The name of the web application to check
*/
public void check(String name) {
DeployedApplication app = deployed.get(name);
if (app != null) {
- checkResources(app, true);
+ if (tryAddServiced(app.name)) {
+ try {
+ checkResources(app, true);
+ } finally {
+ removeServiced(app.name);
+ }
+ }
}
deployApps(name);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 07/07: Allow Manager app to deploy applications in parallel
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit ee6069392752f930c64e160a6a08a9904ffea008
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Feb 1 16:53:59 2021 +0000
Allow Manager app to deploy applications in parallel
Seventh and final patch in a series of patches aimed at allowing
parallel requests to the Manager application to deploy different
applications in parallel rather than using a sync block to deploy them
serially.
The previous refactoring of the list of serviced applications now means
that it is safe for the Manage application to deploy applications in
parallel.
---
java/org/apache/catalina/manager/ManagerServlet.java | 6 ++----
webapps/docs/changelog.xml | 8 ++++++++
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index 8f4b825..37cff7b 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -744,10 +744,8 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
* @param request Servlet request we are processing
* @param smClient i18n messages using the locale of the client
*/
- protected synchronized void deploy
- (PrintWriter writer, String config, ContextName cn,
- String tag, boolean update, HttpServletRequest request,
- StringManager smClient) {
+ protected void deploy(PrintWriter writer, String config, ContextName cn, String tag, boolean update,
+ HttpServletRequest request, StringManager smClient) {
if (config != null && config.length() == 0) {
config = null;
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 8649610..6a2a104 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -125,6 +125,14 @@
</fix>
</changelog>
</subsection>
+ <subsection name="Web applications">
+ <changelog>
+ <fix>
+ Remove the restriction that prevented the Manager web application
+ deploying different web applications in parallel. (markt)
+ </fix>
+ </changelog>
+ </subsection>
</section>
<section name="Tomcat 10.0.2 (markt)" rtext="release in progress">
<subsection name="Catalina">
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 02/07: Switch to the thread-safe method of serviced
application tracking
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit c662de6685572cddb1a82c6fcc35f96bfcaaceb3
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Jan 20 17:33:53 2021 +0000
Switch to the thread-safe method of serviced application tracking
Second in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
---
.../apache/catalina/ha/deploy/FarmWarDeployer.java | 31 ++++++++++----
.../catalina/manager/HTMLManagerServlet.java | 7 ++--
.../apache/catalina/manager/ManagerServlet.java | 48 ++++++++++++++--------
3 files changed, 58 insertions(+), 28 deletions(-)
diff --git a/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java b/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
index 940f581..09f075b 100644
--- a/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
+++ b/java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
@@ -228,8 +228,7 @@ public class FarmWarDeployer extends ClusterListener
File deployable = new File(getDeployDirFile(), name);
try {
String contextName = fmsg.getContextName();
- if (!isServiced(contextName)) {
- addServiced(contextName);
+ if (tryAddServiced(contextName)) {
try {
remove(contextName);
if (!factory.getFile().renameTo(deployable)) {
@@ -262,8 +261,7 @@ public class FarmWarDeployer extends ClusterListener
if (log.isDebugEnabled())
log.debug(sm.getString("farmWarDeployer.msgRxUndeploy",
contextName));
- if (!isServiced(contextName)) {
- addServiced(contextName);
+ if (tryAddServiced(contextName)) {
try {
remove(contextName);
} finally {
@@ -420,8 +418,7 @@ public class FarmWarDeployer extends ClusterListener
// remove locally
if (undeploy) {
try {
- if (!isServiced(contextName)) {
- addServiced(contextName);
+ if (tryAddServiced(contextName)) {
try {
remove(contextName);
} finally {
@@ -458,8 +455,7 @@ public class FarmWarDeployer extends ClusterListener
log.info(sm.getString("farmWarDeployer.modInstall",
cn.getName(), deployWar.getAbsolutePath()));
// install local
- if (!isServiced(cn.getName())) {
- addServiced(cn.getName());
+ if (tryAddServiced(cn.getName())) {
try {
copy(newWar, deployWar);
check(cn.getName());
@@ -594,7 +590,9 @@ public class FarmWarDeployer extends ClusterListener
* @param name The context name
* @return <code>true</code> if the context is being serviced
* @throws Exception Error invoking the deployer
+ * @deprecated Unused. Will be removed in Tomcat 10.1.x onwards.
*/
+ @Deprecated
protected boolean isServiced(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
@@ -607,7 +605,10 @@ public class FarmWarDeployer extends ClusterListener
* Mark a context as being services.
* @param name The context name
* @throws Exception Error invoking the deployer
+ * @deprecated Unused. Will be removed in Tomcat 10.1.x onwards.
+ * Use {@link #tryAddServiced}
*/
+ @Deprecated
protected void addServiced(String name) throws Exception {
String[] params = { name };
String[] signature = { "java.lang.String" };
@@ -615,6 +616,20 @@ public class FarmWarDeployer extends ClusterListener
}
/**
+ * Attempt to mark a context as being serviced
+ * @param name The context name
+ * @return {@code true} if the application was marked as being serviced and
+ * {@code false} if the application was already marked as being serviced
+ * @throws Exception Error invoking the deployer
+ */
+ protected boolean tryAddServiced(String name) throws Exception {
+ String[] params = { name };
+ String[] signature = { "java.lang.String" };
+ Boolean result = (Boolean) mBeanServer.invoke(oname, "tryAddServiced", params, signature);
+ return result.booleanValue();
+ }
+
+ /**
* Mark a context as no longer being serviced.
* @param name The context name
* @throws Exception Error invoking the deployer
diff --git a/java/org/apache/catalina/manager/HTMLManagerServlet.java b/java/org/apache/catalina/manager/HTMLManagerServlet.java
index 749ab83..65601ec 100644
--- a/java/org/apache/catalina/manager/HTMLManagerServlet.java
+++ b/java/org/apache/catalina/manager/HTMLManagerServlet.java
@@ -284,10 +284,7 @@ public final class HTMLManagerServlet extends ManagerServlet {
break;
}
- if (isServiced(name)) {
- message = smClient.getString("managerServlet.inService", name);
- } else {
- addServiced(name);
+ if (tryAddServiced(name)) {
try {
warPart.write(file.getAbsolutePath());
// Perform new deployment
@@ -295,6 +292,8 @@ public final class HTMLManagerServlet extends ManagerServlet {
} finally {
removeServiced(name);
}
+ } else {
+ message = smClient.getString("managerServlet.inService", name);
}
break;
}
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index 52002d7..dd68e1b 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -814,10 +814,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
}
try {
- if (isServiced(name)) {
- writer.println(smClient.getString("managerServlet.inService", displayPath));
- } else {
- addServiced(name);
+ if (tryAddServiced(name)) {
try {
if (config != null) {
if (!configBase.mkdirs() && !configBase.isDirectory()) {
@@ -854,6 +851,8 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
} finally {
removeServiced(name);
}
+ } else {
+ writer.println(smClient.getString("managerServlet.inService", displayPath));
}
} catch (Exception e) {
log(sm.getString("managerServlet.error.deploy", displayPath), e);
@@ -896,10 +895,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
// Copy WAR to appBase
try {
- if (isServiced(name)) {
- writer.println(smClient.getString("managerServlet.inService", displayPath));
- } else {
- addServiced(name);
+ if (tryAddServiced(name)) {
try {
if (!deployedWar.delete()) {
writer.println(smClient.getString("managerServlet.deleteFail",
@@ -912,6 +908,8 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
} finally {
removeServiced(name);
}
+ } else {
+ writer.println(smClient.getString("managerServlet.inService", displayPath));
}
} catch (Exception e) {
log(sm.getString("managerServlet.error.deploy", displayPath), e);
@@ -989,10 +987,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
}
try {
- if (isServiced(name)) {
- writer.println(smClient.getString("managerServlet.inService", displayPath));
- } else {
- addServiced(name);
+ if (tryAddServiced(name)) {
try {
if (config != null) {
if (!configBase.mkdirs() && !configBase.isDirectory()) {
@@ -1027,6 +1022,8 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
} finally {
removeServiced(name);
}
+ } else {
+ writer.println(smClient.getString("managerServlet.inService", displayPath));
}
writeDeployResult(writer, smClient, name, displayPath);
} catch (Throwable t) {
@@ -1498,10 +1495,7 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
return;
}
- if (isServiced(name)) {
- writer.println(smClient.getString("managerServlet.inService", displayPath));
- } else {
- addServiced(name);
+ if (tryAddServiced(name)) {
try {
// Try to stop the context first to be nicer
context.stop();
@@ -1530,6 +1524,8 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
} finally {
removeServiced(name);
}
+ } else {
+ writer.println(smClient.getString("managerServlet.inService", displayPath));
}
writer.println(smClient.getString("managerServlet.undeployed",
displayPath));
@@ -1583,7 +1579,9 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
* @param name The webapp name
* @return <code>true</code> if a webapp with that name is being serviced
* @throws Exception Propagate JMX invocation error
+ * @deprecated Unused. Will be removed in Tomcat 10.1.x onwards.
*/
+ @Deprecated
protected boolean isServiced(String name)
throws Exception {
String[] params = { name };
@@ -1599,7 +1597,10 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
*
* @param name The webapp name
* @throws Exception Propagate JMX invocation error
+ * @deprecated Unused. Will be removed in Tomcat 10.1.x onwards.
+ * Use {@link #tryAddServiced}
*/
+ @Deprecated
protected void addServiced(String name)
throws Exception {
String[] params = { name };
@@ -1609,6 +1610,21 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
/**
+ * Attempt to mark a context as being serviced
+ * @param name The context name
+ * @return {@code true} if the application was marked as being serviced and
+ * {@code false} if the application was already marked as being serviced
+ * @throws Exception Error invoking the deployer
+ */
+ protected boolean tryAddServiced(String name) throws Exception {
+ String[] params = { name };
+ String[] signature = { "java.lang.String" };
+ Boolean result = (Boolean) mBeanServer.invoke(oname, "tryAddServiced", params, signature);
+ return result.booleanValue();
+ }
+
+
+ /**
* Invoke the removeServiced method on the deployer.
*
* @param name The webapp name
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 05/07: Deprecated isServiced as unused
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 3da1d7eb08c0766dd190ab0eb0c7f0b2c6f93093
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Jan 22 19:26:54 2021 +0000
Deprecated isServiced as unused
Fifth in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
---
java/org/apache/catalina/startup/HostConfig.java | 4 ++++
java/org/apache/catalina/startup/mbeans-descriptors.xml | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 5e7ea52..2853199 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -367,7 +367,11 @@ public class HostConfig implements LifecycleListener {
* @param name the context name
*
* @return state of the application
+ *
+ * @deprecated Unused. This method will be removed in Tomcat 10.1.x onwards.
+ * Use {@link #tryAddServiced} instead.
*/
+ @Deprecated
public boolean isServiced(String name) {
return servicedSet.contains(name);
}
diff --git a/java/org/apache/catalina/startup/mbeans-descriptors.xml b/java/org/apache/catalina/startup/mbeans-descriptors.xml
index c66647a..9cdc1bb 100644
--- a/java/org/apache/catalina/startup/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/startup/mbeans-descriptors.xml
@@ -142,7 +142,7 @@
</operation>
<operation name="isServiced"
- description="Is a web application serviced by another component"
+ description="DEPRECATED: Is a web application serviced by another component"
impact="ACTION"
returnType="boolean">
<parameter name="name"
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
[tomcat] 01/07: Refactor tracking of serviced applications to use a
concurrent Set
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch serviced
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 2a7521a1923a3e96ccf2291fa030fc7083559c19
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Jan 20 17:32:28 2021 +0000
Refactor tracking of serviced applications to use a concurrent Set
First in a series of patches aimed at allowing parallel requests to the
Manager application to deploy different applications in parallel rather
than using a sync block to deploy them serially.
Using a List was problematic as it allowed duplicates. This has been
addressed by switching to a Set.
Synchronized blocks have been replaced by using a concurrent Set.
A new method (tryAddServiced) has been added to the process of
checking if an app is being serviced, and registering it as such if
not, so that this can be performed atomically.
serviced has been retained in case it is used by custom sub-classes.
---
java/org/apache/catalina/startup/HostConfig.java | 58 +++++++++++++++++++---
.../apache/catalina/startup/mbeans-descriptors.xml | 11 +++-
2 files changed, 61 insertions(+), 8 deletions(-)
diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java
index 89d002a..3ffc360 100644
--- a/java/org/apache/catalina/startup/HostConfig.java
+++ b/java/org/apache/catalina/startup/HostConfig.java
@@ -31,6 +31,7 @@ import java.security.PermissionCollection;
import java.security.Policy;
import java.security.cert.Certificate;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -147,11 +148,20 @@ public class HostConfig implements LifecycleListener {
/**
* List of applications which are being serviced, and shouldn't be
* deployed/undeployed/redeployed at the moment.
+ * @deprecated Unused. Will be removed in Tomcat 10.1.x onwards. Replaced
+ * by the private <code>servicedSet</code> field.
*/
+ @Deprecated
protected final ArrayList<String> serviced = new ArrayList<>();
/**
+ * Set of applications which are being serviced, and shouldn't be
+ * deployed/undeployed/redeployed at the moment.
+ */
+ private Set<String> servicedSet = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
+
+ /**
* The <code>Digester</code> instance used to parse context descriptors.
*/
protected Digester digester = createDigester(contextClass);
@@ -314,21 +324,52 @@ public class HostConfig implements LifecycleListener {
/**
- * Add a serviced application to the list.
+ * Add a serviced application to the list and indicates if the application
+ * was already present in the list.
+ *
+ * @param name the context name
+ *
+ * @return {@code true} if the application was not already in the list
+ */
+ public boolean tryAddServiced(String name) {
+ if (servicedSet.add(name)) {
+ synchronized (this) {
+ serviced.add(name);
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Add a serviced application to the list if it is not already present. If
+ * the application is already in the list of serviced applications this
+ * method is a NO-OP.
+ *
* @param name the context name
+ *
+ * @deprecated Unused. This method will be removed in Tomcat 10.1.x onwards.
+ * Use {@link #tryAddServiced} instead.
*/
- public synchronized void addServiced(String name) {
- serviced.add(name);
+ @Deprecated
+ public void addServiced(String name) {
+ servicedSet.add(name);
+ synchronized (this) {
+ serviced.add(name);
+ }
}
/**
* Is application serviced ?
+ *
* @param name the context name
+ *
* @return state of the application
*/
- public synchronized boolean isServiced(String name) {
- return serviced.contains(name);
+ public boolean isServiced(String name) {
+ return servicedSet.contains(name);
}
@@ -336,8 +377,11 @@ public class HostConfig implements LifecycleListener {
* Removed a serviced application from the list.
* @param name the context name
*/
- public synchronized void removeServiced(String name) {
- serviced.remove(name);
+ public void removeServiced(String name) {
+ servicedSet.remove(name);
+ synchronized (this) {
+ serviced.remove(name);
+ }
}
diff --git a/java/org/apache/catalina/startup/mbeans-descriptors.xml b/java/org/apache/catalina/startup/mbeans-descriptors.xml
index 303d628..c66647a 100644
--- a/java/org/apache/catalina/startup/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/startup/mbeans-descriptors.xml
@@ -90,8 +90,17 @@
is="true"
type="boolean"/>
+ <operation name="tryAddServiced"
+ description="Add a web application to the serviced list to show it is being serviced by another component returning true if the application was added and false if the application was already being serviced"
+ impact="ACTION"
+ returnType="boolean">
+ <parameter name="name"
+ description="Application name"
+ type="java.lang.String"/>
+ </operation>
+
<operation name="addServiced"
- description="Add a web application to the serviced list to show it gets serviced by another component"
+ description="DEPRECATED: Add a web application to the serviced list to show it is being serviced by another component"
impact="ACTION"
returnType="void">
<parameter name="name"
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org