Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D08D7196EC for ; Mon, 21 Mar 2016 14:20:27 +0000 (UTC) Received: (qmail 18744 invoked by uid 500); 21 Mar 2016 14:20:27 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 18685 invoked by uid 500); 21 Mar 2016 14:20:27 -0000 Mailing-List: contact commits-help@ignite.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.apache.org Delivered-To: mailing list commits@ignite.apache.org Received: (qmail 18470 invoked by uid 99); 21 Mar 2016 14:20:27 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Mar 2016 14:20:27 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 957CDDFFCD; Mon, 21 Mar 2016 14:20:27 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: av@apache.org To: commits@ignite.apache.org Date: Mon, 21 Mar 2016 14:20:56 -0000 Message-Id: <91aaa3f58be849f7bb01d5de72bcac37@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [31/50] [abbrv] ignite git commit: IGNITE-2765 WebSessionFilter doesn't survive client reconnect IGNITE-2765 WebSessionFilter doesn't survive client reconnect Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3130872e Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3130872e Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3130872e Branch: refs/heads/ignite-2801 Commit: 3130872ed3805250310f807ffe0b6e1c8e3e3a99 Parents: cb6da11 Author: Anton Vinogradov Authored: Fri Mar 11 19:23:49 2016 +0300 Committer: Anton Vinogradov Committed: Fri Mar 11 19:23:49 2016 +0300 ---------------------------------------------------------------------- .../config/websession/example-cache-base.xml | 148 +++++++++++++++ .../config/websession/example-cache-client.xml | 33 ++++ .../test/config/websession/example-cache.xml | 128 +------------ .../test/config/websession/example-cache2.xml | 31 +++ .../cache/websession/WebSessionFilter.java | 188 ++++++++++++++----- .../cache/websession/WebSessionListener.java | 60 +++--- .../internal/websession/WebSessionSelfTest.java | 73 +++++++ 7 files changed, 453 insertions(+), 208 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/core/src/test/config/websession/example-cache-base.xml ---------------------------------------------------------------------- diff --git a/modules/core/src/test/config/websession/example-cache-base.xml b/modules/core/src/test/config/websession/example-cache-base.xml new file mode 100644 index 0000000..d3d5b46 --- /dev/null +++ b/modules/core/src/test/config/websession/example-cache-base.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + java.lang.Integer + java.lang.Long + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + java.lang.Integer + java.lang.Integer + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47509 + + + + + + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/core/src/test/config/websession/example-cache-client.xml ---------------------------------------------------------------------- diff --git a/modules/core/src/test/config/websession/example-cache-client.xml b/modules/core/src/test/config/websession/example-cache-client.xml new file mode 100644 index 0000000..9272e14 --- /dev/null +++ b/modules/core/src/test/config/websession/example-cache-client.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/core/src/test/config/websession/example-cache.xml ---------------------------------------------------------------------- diff --git a/modules/core/src/test/config/websession/example-cache.xml b/modules/core/src/test/config/websession/example-cache.xml index 0cc0e1e..1090220 100644 --- a/modules/core/src/test/config/websession/example-cache.xml +++ b/modules/core/src/test/config/websession/example-cache.xml @@ -28,130 +28,12 @@ --> - - - + xsi:schemaLocation="http://www.springframework.org/schema/beans + http://www.springframework.org/schema/beans/spring-beans.xsd"> + + - - - - - - - - - - - - - - - - - - - - - - - - - - java.lang.Integer - java.lang.Long - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - java.lang.Integer - java.lang.Integer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47509 - - - - - - + - - - - - - - - - - - http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/core/src/test/config/websession/example-cache2.xml ---------------------------------------------------------------------- diff --git a/modules/core/src/test/config/websession/example-cache2.xml b/modules/core/src/test/config/websession/example-cache2.xml new file mode 100644 index 0000000..59a244f --- /dev/null +++ b/modules/core/src/test/config/websession/example-cache2.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java index bd2f25f..02b5f65 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java @@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpSession; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteClientDisconnectedException; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.IgniteTransactions; @@ -123,6 +124,15 @@ import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_REA * * {@code 3} * + * + * IgniteWebSessionsRetriesTimeout + * + * Retry timeout. Related to IgniteWebSessionsMaximumRetriesOnFail param. + *

+ * Further attempts will be cancelled in case timeout was exceeded. + * + * {@code 10000} (10 seconds) + * * * These parameters are taken from either filter init parameter list or * servlet context parameters. You can specify filter init parameters as follows: @@ -169,9 +179,15 @@ public class WebSessionFilter implements Filter { /** Web sessions caching retry on fail parameter name (valid for ATOMIC cache only). */ public static final String WEB_SES_MAX_RETRIES_ON_FAIL_NAME_PARAM = "IgniteWebSessionsMaximumRetriesOnFail"; + /** Web sessions caching retry on fail timeout parameter name. */ + public static final String WEB_SES_RETRIES_TIMEOUT_NAME_PARAM = "IgniteWebSessionsRetriesTimeout"; + /** Default retry on fail flag value. */ public static final int DFLT_MAX_RETRIES_ON_FAIL = 3; + /** Default retry on fail timeout flag value. */ + public static final int DFLT_RETRIES_ON_FAIL_TIMEOUT = 10000; + /** Cache. */ private IgniteCache cache; @@ -193,9 +209,18 @@ public class WebSessionFilter implements Filter { /** Transactions enabled flag. */ private boolean txEnabled; + /** Node. */ + private Ignite webSesIgnite; + + /** Cache name. */ + private String cacheName; + /** */ private int retries; + /** */ + private int retriesTimeout; + /** {@inheritDoc} */ @Override public void init(FilterConfig cfg) throws ServletException { ctx = cfg.getServletContext(); @@ -204,7 +229,7 @@ public class WebSessionFilter implements Filter { cfg.getInitParameter(WEB_SES_NAME_PARAM), ctx.getInitParameter(WEB_SES_NAME_PARAM)); - String cacheName = U.firstNotNull( + cacheName = U.firstNotNull( cfg.getInitParameter(WEB_SES_CACHE_NAME_PARAM), ctx.getInitParameter(WEB_SES_CACHE_NAME_PARAM)); @@ -219,7 +244,19 @@ public class WebSessionFilter implements Filter { throw new IgniteException("Maximum number of retries parameter is invalid: " + retriesStr, e); } - Ignite webSesIgnite = G.ignite(gridName); + String retriesTimeoutStr = U.firstNotNull( + cfg.getInitParameter(WEB_SES_RETRIES_TIMEOUT_NAME_PARAM), + ctx.getInitParameter(WEB_SES_RETRIES_TIMEOUT_NAME_PARAM)); + + try { + retriesTimeout = retriesTimeoutStr != null ? + Integer.parseInt(retriesTimeoutStr) : DFLT_RETRIES_ON_FAIL_TIMEOUT; + } + catch (NumberFormatException e) { + throw new IgniteException("Retries timeout parameter is invalid: " + retriesTimeoutStr, e); + } + + webSesIgnite = G.ignite(gridName); if (webSesIgnite == null) throw new IgniteException("Grid for web sessions caching is not started (is it configured?): " + @@ -229,35 +266,9 @@ public class WebSessionFilter implements Filter { log = webSesIgnite.log(); - cache = webSesIgnite.cache(cacheName); - - if (cache == null) - throw new IgniteException("Cache for web sessions is not started (is it configured?): " + cacheName); - - CacheConfiguration cacheCfg = cache.getConfiguration(CacheConfiguration.class); - - if (cacheCfg.getWriteSynchronizationMode() == FULL_ASYNC) - throw new IgniteException("Cache for web sessions cannot be in FULL_ASYNC mode: " + cacheName); - - if (!cacheCfg.isEagerTtl()) - throw new IgniteException("Cache for web sessions cannot operate with lazy TTL. " + - "Consider setting eagerTtl to true for cache: " + cacheName); - - if (cacheCfg.getCacheMode() == LOCAL) - U.quietAndWarn(webSesIgnite.log(), "Using LOCAL cache for web sessions caching " + - "(this is only OK in test mode): " + cacheName); + initCache(); - if (cacheCfg.getCacheMode() == PARTITIONED && cacheCfg.getAtomicityMode() != ATOMIC) - U.quietAndWarn(webSesIgnite.log(), "Using " + cacheCfg.getAtomicityMode() + " atomicity for web sessions " + - "caching (switch to ATOMIC mode for better performance)"); - - if (log.isInfoEnabled()) - log.info("Started web sessions caching [gridName=" + gridName + ", cacheName=" + cacheName + - ", maxRetriesOnFail=" + retries + ']'); - - txEnabled = cacheCfg.getAtomicityMode() == TRANSACTIONAL; - - lsnr = new WebSessionListener(webSesIgnite, cache, retries); + lsnr = new WebSessionListener(webSesIgnite, this, retries); String srvInfo = ctx.getServerInfo(); @@ -286,6 +297,46 @@ public class WebSessionFilter implements Filter { } }; } + + if (log.isInfoEnabled()) + log.info("Started web sessions caching [gridName=" + gridName + ", cacheName=" + cacheName + + ", maxRetriesOnFail=" + retries + ']'); + } + + /** + * @return Cache. + */ + IgniteCache getCache(){ + return cache; + } + + /** + * Init cache. + */ + void initCache() { + cache = webSesIgnite.cache(cacheName); + + if (cache == null) + throw new IgniteException("Cache for web sessions is not started (is it configured?): " + cacheName); + + CacheConfiguration cacheCfg = cache.getConfiguration(CacheConfiguration.class); + + if (cacheCfg.getWriteSynchronizationMode() == FULL_ASYNC) + throw new IgniteException("Cache for web sessions cannot be in FULL_ASYNC mode: " + cacheName); + + if (!cacheCfg.isEagerTtl()) + throw new IgniteException("Cache for web sessions cannot operate with lazy TTL. " + + "Consider setting eagerTtl to true for cache: " + cacheName); + + if (cacheCfg.getCacheMode() == LOCAL) + U.quietAndWarn(webSesIgnite.log(), "Using LOCAL cache for web sessions caching " + + "(this is only OK in test mode): " + cacheName); + + if (cacheCfg.getCacheMode() == PARTITIONED && cacheCfg.getAtomicityMode() != ATOMIC) + U.quietAndWarn(webSesIgnite.log(), "Using " + cacheCfg.getAtomicityMode() + " atomicity for web sessions " + + "caching (switch to ATOMIC mode for better performance)"); + + txEnabled = cacheCfg.getAtomicityMode() == TRANSACTIONAL; } /** {@inheritDoc} */ @@ -333,7 +384,7 @@ public class WebSessionFilter implements Filter { */ private String doFilter0(HttpServletRequest httpReq, ServletResponse res, FilterChain chain) throws IOException, ServletException, CacheException { - WebSession cached; + WebSession cached = null; String sesId = httpReq.getRequestedSessionId(); @@ -341,7 +392,24 @@ public class WebSessionFilter implements Filter { if (sesIdTransformer != null) sesId = sesIdTransformer.apply(sesId); - cached = cache.get(sesId); + for (int i = 0; i < retries; i++) { + try { + cached = cache.get(sesId); + } + catch (CacheException | IgniteException | IllegalStateException e) { + if (log.isDebugEnabled()) + log.debug(e.getMessage()); + + if (i == retries - 1) + throw new IgniteException("Failed to handle request [session= " + sesId + "]", e); + else { + if (log.isDebugEnabled()) + log.debug("Failed to handle request (will retry): " + sesId); + + handleCacheOperationException(e); + } + } + } if (cached != null) { if (log.isDebugEnabled()) @@ -438,7 +506,7 @@ public class WebSessionFilter implements Filter { break; } - catch (CacheException | IgniteException e) { + catch (CacheException | IgniteException | IllegalStateException e) { if (log.isDebugEnabled()) log.debug(e.getMessage()); @@ -448,29 +516,49 @@ public class WebSessionFilter implements Filter { if (log.isDebugEnabled()) log.debug("Failed to save session (will retry): " + sesId); - IgniteFuture retryFut = null; + handleCacheOperationException(e); + } + } + } - if (X.hasCause(e, ClusterTopologyException.class)) { - ClusterTopologyException cause = X.cause(e, ClusterTopologyException.class); + return cached; + } - assert cause != null : e; + /** + * Handles cache operation exception. + * @param e Exception + */ + void handleCacheOperationException(Exception e){ + IgniteFuture retryFut = null; - retryFut = cause.retryReadyFuture(); - } + if (e instanceof IllegalStateException) { + initCache(); - if (retryFut != null) { - try { - retryFut.get(); - } - catch (IgniteException retryErr) { - throw new IgniteException("Failed to save session: " + sesId, retryErr); - } - } - } - } + return; } + else if (X.hasCause(e, IgniteClientDisconnectedException.class)) { + IgniteClientDisconnectedException cause = X.cause(e, IgniteClientDisconnectedException.class); - return cached; + assert cause != null : e; + + retryFut = cause.reconnectFuture(); + } + else if (X.hasCause(e, ClusterTopologyException.class)) { + ClusterTopologyException cause = X.cause(e, ClusterTopologyException.class); + + assert cause != null : e; + + retryFut = cause.retryReadyFuture(); + } + + if (retryFut != null) { + try { + retryFut.get(retriesTimeout); + } + catch (IgniteException retryErr) { + throw new IgniteException("Failed to wait for retry: " + retryErr); + } + } } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java index 0d7c44e..0d8ffec 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionListener.java @@ -32,12 +32,9 @@ import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; -import org.apache.ignite.cluster.ClusterTopologyException; import org.apache.ignite.internal.util.typedef.T2; -import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.lang.IgniteFuture; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -45,11 +42,8 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; * Session listener for web sessions caching. */ class WebSessionListener { - /** */ - private static final long RETRY_DELAY = 1000; - - /** Cache. */ - private final IgniteCache cache; + /** Filter. */ + private final WebSessionFilter filter; /** Maximum retries. */ private final int retries; @@ -59,14 +53,14 @@ class WebSessionListener { /** * @param ignite Grid. - * @param cache Cache. + * @param filter Filter. * @param retries Maximum retries. */ - WebSessionListener(Ignite ignite, IgniteCache cache, int retries) { + WebSessionListener(Ignite ignite, WebSessionFilter filter, int retries) { assert ignite != null; - assert cache != null; + assert filter != null; - this.cache = cache; + this.filter = filter; this.retries = retries > 0 ? retries : 1; log = ignite.log(); @@ -77,13 +71,22 @@ class WebSessionListener { */ public void destroySession(String sesId) { assert sesId != null; + for (int i = 0; i < retries; i++) { + try { + if (filter.getCache().remove(sesId) && log.isDebugEnabled()) + log.debug("Session destroyed: " + sesId); + } + catch (CacheException | IgniteException | IllegalStateException e) { + if (i == retries - 1) { + U.warn(log, "Failed to remove session [sesId=" + + sesId + ", retries=" + retries + ']'); + } + else { + U.warn(log, "Failed to remove session (will retry): " + sesId); - try { - if (cache.remove(sesId) && log.isDebugEnabled()) - log.debug("Session destroyed: " + sesId); - } - catch (CacheException e) { - U.error(log, "Failed to remove session: " + sesId, e); + filter.handleCacheOperationException(e); + } + } } } @@ -110,16 +113,16 @@ class WebSessionListener { ExpiryPolicy plc = new ModifiedExpiryPolicy(new Duration(MILLISECONDS, ttl)); - cache0 = cache.withExpiryPolicy(plc); + cache0 = filter.getCache().withExpiryPolicy(plc); } else - cache0 = cache; + cache0 = filter.getCache(); cache0.invoke(sesId, new AttributesProcessor(updates)); break; } - catch (CacheException | IgniteException e) { + catch (CacheException | IgniteException | IllegalStateException e) { if (i == retries - 1) { U.warn(log, "Failed to apply updates for session (maximum number of retries exceeded) [sesId=" + sesId + ", retries=" + retries + ']'); @@ -127,20 +130,7 @@ class WebSessionListener { else { U.warn(log, "Failed to apply updates for session (will retry): " + sesId); - IgniteFuture retryFut = null; - - if (X.hasCause(e, ClusterTopologyException.class)) { - ClusterTopologyException cause = X.cause(e, ClusterTopologyException.class); - - assert cause != null : e; - - retryFut = cause.retryReadyFuture(); - } - - if (retryFut != null) - retryFut.get(); - else - U.sleep(RETRY_DELAY); + filter.handleCacheOperationException(e); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/3130872e/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java index 7a321d6..90cb132 100644 --- a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java +++ b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java @@ -32,7 +32,9 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; +import org.apache.ignite.Ignition; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.X; @@ -76,6 +78,77 @@ public class WebSessionSelfTest extends GridCommonAbstractTest { } /** + * @throws Exception If failed. + */ + public void testClientReconnectRequest() throws Exception { + testClientReconnectRequest("/modules/core/src/test/config/websession/example-cache.xml", + "/modules/core/src/test/config/websession/example-cache2.xml", + "/modules/core/src/test/config/websession/example-cache-client.xml"); + } + + /** + * Tests single request to a server. Checks the presence of session in cache. + * + * @param srvCfg Server configuration. + * @param clientCfg Client configuration. + * @throws Exception If failed. + */ + private void testClientReconnectRequest(String srvCfg, String srvCfg2, String clientCfg) throws Exception { + Server srv = null; + + Ignite ignite = Ignition.start(srvCfg); + + try { + srv = startServer(TEST_JETTY_PORT, clientCfg, "client", new SessionCreateServlet()); + + URL url = new URL("http://localhost:" + TEST_JETTY_PORT + "/ignitetest/test"); + + URLConnection conn = url.openConnection(); + + conn.connect(); + + try (BufferedReader rdr = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String sesId = rdr.readLine(); + + assertNotNull(sesId); + } + + stopGrid(ignite.name()); + + ignite = Ignition.start(srvCfg); + + conn = url.openConnection(); + + conn.connect(); + + try (BufferedReader rdr = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String sesId = rdr.readLine(); + + assertNotNull(sesId); + } + + Ignite ignite2 = Ignition.start(srvCfg2); + + stopGrid(ignite.name()); + + conn = url.openConnection(); + + conn.connect(); + + try (BufferedReader rdr = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String sesId = rdr.readLine(); + + assertNotNull(sesId); + } + } + finally { + stopServer(srv); + + stopAllGrids(); + } + } + + /** * Tests single request to a server. Checks the presence of session in cache. * * @param cfg Configuration.