diff options
author | Fabian Lange <lange.fabian@gmail.com> | 2014-07-12 00:00:41 +0200 |
---|---|---|
committer | Fabian Lange <lange.fabian@gmail.com> | 2014-07-21 13:55:59 +0200 |
commit | 4fafa9dbbccc387e0bd3c1a0d44f74b3a111b06c (patch) | |
tree | a3a0952d5575f1c6939b657d84e494405d72a078 /server | |
parent | a197bd64db7521749c16551cc238890aea0fa113 (diff) | |
download | vaadin-framework-4fafa9dbbccc387e0bd3c1a0d44f74b3a111b06c.tar.gz vaadin-framework-4fafa9dbbccc387e0bd3c1a0d44f74b3a111b06c.zip |
Improves performance of VaadinService.requestEnd(). (#14218)
Doing two times session.accessSynchronously is unnecessary effort in
multiple aspects:
* The session will be locked twice.
* CurrentInstances are set twice.
* CurrentInstances are restored twice.
* VaadinSession being checked for being the current via
VaadinService.verifyNoOtherSessionLocked(this);
When we leave requestEnd we unset all CurrentInstances. There is no need
to just restore them before doing so.
When we are in requestEnd, VaadinSession is set to "current" by
PushHandler.callWithUi() or VaadinService.handleRequest().
Also, the cleanupSession code does not need any of these thread locals,
so not having them set would also not hurt.
having an extra accessSynchronously call for just setting the duration
does not make a lot of sense. While it somehow wants to make the previous
accessSynchronously call to be counted completely into the duration it
invests an the same time that would have been left out additionally.
VaadinService removeClosedUIs is a cleanup which also locks and sets
CurrentInstances just to figure out that the UI it is checking is not
closing. This change moves that check out of ui.accessSynchronously.
In the end, the resulting code is a tiny bit less robust, however it
eliminates over 50% response time on trivial push request/responses.
Change-Id: If71d1dbbae5d1fd57d3d4e735c592fd263261a81
Diffstat (limited to 'server')
-rw-r--r-- | server/src/com/vaadin/server/VaadinService.java | 39 | ||||
-rw-r--r-- | server/src/com/vaadin/server/VaadinSession.java | 215 |
2 files changed, 124 insertions, 130 deletions
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java index 442e2fa83c..8d44ff74ed 100644 --- a/server/src/com/vaadin/server/VaadinService.java +++ b/server/src/com/vaadin/server/VaadinService.java @@ -1173,16 +1173,16 @@ public abstract class VaadinService implements Serializable { private void removeClosedUIs(final VaadinSession session) { ArrayList<UI> uis = new ArrayList<UI>(session.getUIs()); for (final UI ui : uis) { - ui.accessSynchronously(new Runnable() { - @Override - public void run() { - if (ui.isClosing()) { + if (ui.isClosing()) { + ui.accessSynchronously(new Runnable() { + @Override + public void run() { getLogger().log(Level.FINER, "Removing closed UI {0}", ui.getUIId()); session.removeUI(ui); } - } - }); + }); + } } } @@ -1338,23 +1338,16 @@ public abstract class VaadinService implements Serializable { public void requestEnd(VaadinRequest request, VaadinResponse response, VaadinSession session) { if (session != null) { - final VaadinSession finalSession = session; - - session.accessSynchronously(new Runnable() { - @Override - public void run() { - cleanupSession(finalSession); - } - }); - - final long duration = (System.nanoTime() - (Long) request - .getAttribute(REQUEST_START_TIME_ATTRIBUTE)) / 1000000; - session.accessSynchronously(new Runnable() { - @Override - public void run() { - finalSession.setLastRequestDuration(duration); - } - }); + assert VaadinSession.getCurrent() == session; + session.lock(); + try { + cleanupSession(session); + final long duration = (System.nanoTime() - (Long) request + .getAttribute(REQUEST_START_TIME_ATTRIBUTE)) / 1000000; + session.setLastRequestDuration(duration); + } finally { + session.unlock(); + } } CurrentInstance.clearAll(); } diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java index bbabd881f8..2ab8c52dad 100644 --- a/server/src/com/vaadin/server/VaadinSession.java +++ b/server/src/com/vaadin/server/VaadinSession.java @@ -1,12 +1,12 @@ /* * Copyright 2000-2014 Vaadin Ltd. - * + * * Licensed 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 @@ -65,7 +65,7 @@ import com.vaadin.util.ReflectTools; * Everything inside a {@link VaadinSession} should be serializable to ensure * compatibility with schemes using serialization for persisting the session * data. - * + * * @author Vaadin Ltd * @since 7.0.0 */ @@ -77,7 +77,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * {@link VaadinSession#access(Runnable)}. This class is used internally by * the framework and is not intended to be directly used by application * developers. - * + * * @since 7.1 * @author Vaadin Ltd */ @@ -93,10 +93,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Creates an instance for the given runnable - * + * * @param session * the session to which the task belongs - * + * * @param runnable * the runnable to run when this task is purged from the * queue @@ -114,7 +114,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * deadlocks unless implemented very carefully. get(long, TimeUnit) * does not have the same detection since a sensible timeout should * avoid completely locking up the application. - * + * * Even though no deadlock could occur after the runnable has been * run, the check is always done as the deterministic behavior makes * it easier to detect potential problems. @@ -126,9 +126,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the current instance values that should be used when running * this task. - * + * * @see CurrentInstance#restoreInstances(Map) - * + * * @return a map of current instances. */ public Map<Class<?>, CurrentInstance> getCurrentInstances() { @@ -137,7 +137,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Handles exceptions thrown during the execution of this task. - * + * * @since 7.1.8 * @param exception * the thrown exception. @@ -168,7 +168,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * The lifecycle state of a VaadinSession. - * + * * @since 7.2 */ public enum State { @@ -273,7 +273,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Creates a new VaadinSession tied to a VaadinService. - * + * * @param service * the Vaadin service for the new session */ @@ -327,9 +327,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Get the web browser associated with this session. - * + * * @return the web browser object - * + * * @deprecated As of 7.0, use {@link Page#getWebBrowser()} instead. */ @Deprecated @@ -350,7 +350,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Sets the time spent servicing the last request in the session and updates * the total time spent servicing requests in this session. - * + * * @param time * The time spent in the last request, in milliseconds. */ @@ -371,11 +371,11 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Sets the time when the last UIDL request was serviced in this session. - * + * * @param timestamp * The time when the last request was handled, in milliseconds * since the epoch. - * + * */ public void setLastRequestTimestamp(long timestamp) { assert hasLock(); @@ -384,7 +384,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Returns the time when the last request was serviced in this session. - * + * * @return The time when the last request was handled, in milliseconds since * the epoch. */ @@ -396,7 +396,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the underlying session to which this service session is currently * associated. - * + * * @return the wrapped session for this context */ public WrappedSession getSession() { @@ -410,7 +410,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * @return - * + * * @deprecated As of 7.0. Will likely change or be removed in a future * version */ @@ -430,7 +430,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Loads the VaadinSession for the given service and WrappedSession from the * HTTP session. - * + * * @param service * The service the VaadinSession is associated with * @param underlyingSession @@ -460,7 +460,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Retrieves all {@link VaadinSession}s which are stored in the given HTTP * session - * + * * @since 7.2 * @param httpSession * the HTTP session @@ -485,7 +485,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Removes this VaadinSession from the HTTP session. - * + * * @param service * The service this session is associated with * @deprecated As of 7.0. Should be moved to a separate session storage @@ -500,7 +500,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Retrieves the name of the attribute used for storing a VaadinSession for * the given service. - * + * * @param service * The service associated with the sessio * @return The attribute name used for storing the session @@ -511,7 +511,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Stores this VaadinSession in the HTTP session. - * + * * @param service * The service this session is associated with * @param session @@ -564,7 +564,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the configuration for this session - * + * * @return the deployment configuration */ public DeploymentConfiguration getConfiguration() { @@ -574,10 +574,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the default locale for this session. - * + * * By default this is the preferred locale of the user using the session. In * most cases it is read from the browser defaults. - * + * * @return the locale of this session. */ public Locale getLocale() { @@ -590,13 +590,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Sets the default locale for this session. - * + * * By default this is the preferred locale of the user using the * application. In most cases it is read from the browser defaults. - * + * * @param locale * the Locale object. - * + * */ public void setLocale(Locale locale) { assert hasLock(); @@ -605,7 +605,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the session's error handler. - * + * * @return the current error handler */ public ErrorHandler getErrorHandler() { @@ -615,7 +615,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Sets the session error handler. - * + * * @param errorHandler */ public void setErrorHandler(ErrorHandler errorHandler) { @@ -626,9 +626,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the {@link ConverterFactory} used to locate a suitable * {@link Converter} for fields in the session. - * + * * See {@link #setConverterFactory(ConverterFactory)} for more details - * + * * @return The converter factory used in the session */ public ConverterFactory getConverterFactory() { @@ -653,7 +653,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * </p> * <p> * The converter factory must never be set to null. - * + * * @param converterFactory * The converter factory used in the session */ @@ -670,12 +670,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Handlers are called in reverse order of addition, so the most recently * added handler will be called first. * </p> - * + * * @param handler * the request handler to add - * + * * @see #removeRequestHandler(RequestHandler) - * + * * @since 7.0 */ public void addRequestHandler(RequestHandler handler) { @@ -685,10 +685,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Removes a request handler from the session. - * + * * @param handler * the request handler to remove - * + * * @since 7.0 */ public void removeRequestHandler(RequestHandler handler) { @@ -700,13 +700,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Gets the request handlers that are registered to the session. The * iteration order of the returned collection is the same as the order in * which the request handlers will be invoked when a request is handled. - * + * * @return a collection of request handlers, with the iteration order * according to the order they would be invoked - * + * * @see #addRequestHandler(RequestHandler) * @see #removeRequestHandler(RequestHandler) - * + * * @since 7.0 */ public Collection<RequestHandler> getRequestHandlers() { @@ -721,12 +721,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * {@link InheritableThreadLocal}). In other cases, (e.g. from background * threads started in some other way), the current session is not * automatically defined. - * + * * @return the current session instance if available, otherwise * <code>null</code> - * + * * @see #setCurrent(VaadinSession) - * + * * @since 7.0 */ public static VaadinSession getCurrent() { @@ -742,12 +742,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * session outside the normal request handling and treads started from * request handling threads, e.g. when initiating custom background threads. * </p> - * + * * @param session - * + * * @see #getCurrent() * @see ThreadLocal - * + * * @since 7.0 */ public static void setCurrent(VaadinSession session) { @@ -758,9 +758,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Gets all the UIs of this session. This includes UIs that have been * requested but not yet initialized. UIs that receive no heartbeat requests * from the client are eventually removed from the session. - * + * * @return a collection of UIs belonging to this application - * + * * @since 7.0 */ public Collection<UI> getUIs() { @@ -775,11 +775,11 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Generate an id for the given Connector. Connectors must not call this * method more than once, the first time they need an id. - * + * * @param connector * A connector that has not yet been assigned an id. * @return A new id for the connector - * + * * @deprecated As of 7.0. Will likely change or be removed in a future * version */ @@ -794,7 +794,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * <p> * This is meant for framework internal use. * </p> - * + * * @param uiId * The UI id * @return The UI with the given id or null if not found @@ -806,7 +806,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Checks if the current thread has exclusive access to this VaadinSession - * + * * @return true if the thread has exclusive access, false otherwise */ public boolean hasLock() { @@ -817,7 +817,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Checks if the current thread has exclusive access to the given * WrappedSession. - * + * * @return true if this thread has exclusive access, false otherwise */ private static boolean hasLock(VaadinService service, WrappedSession session) { @@ -830,10 +830,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * be generated. This can be used to modify the contents of the HTML that * loads the Vaadin application in the browser and the HTTP headers that are * included in the response serving the HTML. - * + * * @see BootstrapListener#modifyBootstrapFragment(BootstrapFragmentResponse) * @see BootstrapListener#modifyBootstrapPage(BootstrapPageResponse) - * + * * @param listener * the bootstrap listener to add */ @@ -847,9 +847,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Remove a bootstrap listener that was previously added. - * + * * @see #addBootstrapListener(BootstrapListener) - * + * * @param listener * the bootstrap listener to remove */ @@ -865,11 +865,11 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Fires a bootstrap event to all registered listeners. There are currently * two supported events, both inheriting from {@link BootstrapResponse}: * {@link BootstrapFragmentResponse} and {@link BootstrapPageResponse}. - * + * * @param response * the bootstrap response event for which listeners should be * fired - * + * * @deprecated As of 7.0. Will likely change or be removed in a future * version */ @@ -882,12 +882,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Called by the framework to remove an UI instance from the session because * it has been closed. - * + * * @param ui * the UI to remove */ public void removeUI(UI ui) { assert hasLock(); + assert UI.getCurrent() == ui; Integer id = Integer.valueOf(ui.getUIId()); ui.setSession(null); uIs.remove(id); @@ -902,7 +903,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * connector resources that are not served by any single connector because * e.g. because they are served with strong caching or because of legacy * reasons. - * + * * @param createOnDemand * <code>true</code> if a resource handler should be initialized * if there is no handler associated with this application. @@ -911,7 +912,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * @return this session's global resource handler, or <code>null</code> if * there is no handler and the createOnDemand parameter is * <code>false</code>. - * + * * @since 7.0.0 */ public GlobalResourceHandler getGlobalResourceHandler(boolean createOnDemand) { @@ -933,10 +934,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * instance is not guaranteed to support any other features of the * <code>Lock</code> interface than {@link Lock#lock()} and * {@link Lock#unlock()}. - * + * * @return the <code>Lock</code> that is used for synchronization, never * <code>null</code> - * + * * @see #lock() * @see Lock */ @@ -951,7 +952,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * is done correctly is to wrap your code using {@link UI#access(Runnable)} * (or {@link VaadinSession#access(Runnable)} if you are only touching the * session and not any UI), e.g.: - * + * * <pre> * myUI.access(new Runnable() { * @Override @@ -962,10 +963,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * } * }); * </pre> - * + * * If you for whatever reason want to do locking manually, you should do it * like: - * + * * <pre> * session.lock(); * try { @@ -974,12 +975,12 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * session.unlock(); * } * </pre> - * + * * This method will block until the lock can be retrieved. * <p> * {@link #getLockInstance()} can be used if more control over the locking * is required. - * + * * @see #unlock() * @see #getLockInstance() * @see #hasLock() @@ -995,7 +996,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * For UIs in this session that have its push mode set to * {@link PushMode#AUTOMATIC automatic}, pending changes will be pushed to * their respective clients. - * + * * @see #lock() * @see UI#push() */ @@ -1045,9 +1046,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * data with the current user so that it can be retrieved at a later point * from some other part of the application. Setting the value to * <code>null</code> clears the stored value. - * + * * @see #getAttribute(String) - * + * * @param name * the name to associate the value with, can not be * <code>null</code> @@ -1077,10 +1078,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * value. The outcome of calling this method is thus the same as if calling<br /> * <br /> * <code>setAttribute(type.getName(), value);</code> - * + * * @see #getAttribute(Class) * @see #setAttribute(String, Object) - * + * * @param type * the type that the stored value represents, can not be null * @param value @@ -1104,9 +1105,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Gets a stored attribute value. If a value has been stored for the * session, that value is returned. If no value is stored for the name, * <code>null</code> is returned. - * + * * @see #setAttribute(String, Object) - * + * * @param name * the name of the value to get, can not be <code>null</code>. * @return the value, or <code>null</code> if no value has been stored or if @@ -1129,10 +1130,10 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * value. The outcome of calling this method is thus the same as if calling<br /> * <br /> * <code>getAttribute(type.getName());</code> - * + * * @see #setAttribute(Class, Object) * @see #getAttribute(String) - * + * * @param type * the type of the value to get, can not be <code>null</code>. * @return the value, or <code>null</code> if no value has been stored or if @@ -1153,7 +1154,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Creates a new unique id for a UI. - * + * * @return a unique UI id */ public int getNextUIid() { @@ -1163,7 +1164,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Adds an initialized UI to this session. - * + * * @param ui * the initialized UI to add. */ @@ -1197,7 +1198,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Adds a UI provider to this session. - * + * * @param uiProvider * the UI provider that should be added */ @@ -1208,7 +1209,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Removes a UI provider association from this session. - * + * * @param uiProvider * the UI provider that should be removed */ @@ -1219,7 +1220,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the UI providers configured for this session. - * + * * @return an unmodifiable list of UI providers */ public List<UIProvider> getUIProviders() { @@ -1243,9 +1244,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * To avoid causing out of sync errors, you should typically redirect to * some other page using {@link Page#setLocation(String)} to make the * browser unload the invalidated UI. - * + * * @see SystemMessages#getSessionExpiredCaption() - * + * */ public void close() { assert hasLock(); @@ -1255,13 +1256,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Returns whether this session is marked to be closed. Note that this * method also returns true if the session is actually already closed. - * + * * @see #close() - * + * * @deprecated As of 7.2, use * <code>{@link #getState() getState() != State.OPEN}</code> * instead. - * + * * @return true if this session is marked to be closed, false otherwise */ @Deprecated @@ -1272,7 +1273,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Returns the lifecycle state of this session. - * + * * @since 7.2 * @return the current state */ @@ -1284,7 +1285,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Sets the lifecycle state of this session. The allowed transitions are * OPEN to CLOSING and CLOSING to CLOSED. - * + * * @since 7.2 * @param state * the new state @@ -1323,15 +1324,15 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * later point in time.</li> * </ul> * </p> - * + * * @param runnable * the runnable which accesses the session - * + * * @throws IllegalStateException * if the current thread holds the lock for another session - * + * * @since 7.1 - * + * * @see #lock() * @see #getCurrent() * @see #access(Runnable) @@ -1385,14 +1386,14 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * an exception if it is detected that the current thread holds the lock for * some other session. * </p> - * + * * @see #lock() * @see #getCurrent() * @see #accessSynchronously(Runnable) * @see UI#access(Runnable) - * + * * @since 7.1 - * + * * @param runnable * the runnable which accesses the session * @return a future that can be used to check for task completion and to @@ -1406,9 +1407,9 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { * Gets the queue of tasks submitted using {@link #access(Runnable)}. It is * safe to call this method and access the returned queue without holding * the {@link #lock() session lock}. - * + * * @since 7.1 - * + * * @return the queue of pending access tasks */ public Queue<FutureAccess> getPendingAccessQueue() { @@ -1418,7 +1419,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Gets the CSRF token (aka double submit cookie) that is used to protect * against Cross Site Request Forgery attacks. - * + * * @since 7.1 * @return the csrf token string */ @@ -1439,13 +1440,13 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable { /** * Finds the UI with the corresponding embed id. - * + * * @since 7.2 * @param embedId * the embed id * @return the UI with the corresponding embed id, or <code>null</code> if * no UI is found - * + * * @see UI#getEmbedId() */ public UI getUIByEmbedId(String embedId) { |