View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server.session;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  import static org.junit.Assert.assertNotNull;
24  
25  import java.io.IOException;
26  import java.io.PrintWriter;
27  import java.util.Random;
28  import java.util.concurrent.CyclicBarrier;
29  import java.util.concurrent.ExecutorService;
30  import java.util.concurrent.Executors;
31  import java.util.concurrent.TimeUnit;
32  
33  import javax.servlet.ServletException;
34  import javax.servlet.http.HttpServlet;
35  import javax.servlet.http.HttpServletRequest;
36  import javax.servlet.http.HttpServletResponse;
37  import javax.servlet.http.HttpSession;
38  
39  import org.eclipse.jetty.client.HttpClient;
40  import org.eclipse.jetty.client.api.ContentResponse;
41  import org.eclipse.jetty.client.api.Request;
42  import org.junit.Test;
43  
44  
45  /**
46   * AbstractSameNodeLoadTest
47   * 
48   * This test performs multiple concurrent requests for the same session on the same node.
49   * 
50   */
51  public abstract class AbstractSameNodeLoadTest
52  {
53      protected boolean _stress = Boolean.getBoolean( "STRESS" );
54  
55      public abstract AbstractTestServer createServer(int port);
56  
57      @Test
58      public void testLoad() throws Exception
59      {
60          if ( _stress )
61          {
62              String contextPath = "";
63              String servletMapping = "/server";
64              AbstractTestServer server1 = createServer( 0 );
65              server1.addContext( contextPath ).addServlet( TestServlet.class, servletMapping );
66  
67              try
68              {
69                  server1.start();
70                  int port1 = server1.getPort();
71  
72                  HttpClient client = new HttpClient();
73                  client.start();
74                  try
75                  {
76                      String url = "http://localhost:" + port1 + contextPath + servletMapping;
77  
78  
79                      //create session via first server
80                      ContentResponse response1 = client.GET(url + "?action=init");
81                      assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
82                      String sessionCookie = response1.getHeaders().getStringField( "Set-Cookie" );
83                      assertTrue(sessionCookie != null);
84                      // Mangle the cookie, replacing Path with $Path, etc.
85                      sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
86  
87                      //simulate 10 clients making 100 requests each
88                      ExecutorService executor = Executors.newCachedThreadPool();
89                      int clientsCount = 10;
90                      CyclicBarrier barrier = new CyclicBarrier( clientsCount + 1 );
91                      int requestsCount = 100;
92                      Worker[] workers = new Worker[clientsCount];
93                      for ( int i = 0; i < clientsCount; ++i )
94                      {
95                          workers[i] = new Worker(barrier, client, requestsCount, sessionCookie, url);
96                          executor.execute( workers[i] );
97                      }
98                      // Wait for all workers to be ready
99                      barrier.await();
100                     long start = System.nanoTime();
101 
102                     // Wait for all workers to be done
103                     barrier.await();
104                     long end = System.nanoTime();
105                     long elapsed = TimeUnit.NANOSECONDS.toMillis( end - start );
106                     System.out.println( "elapsed ms: " + elapsed );
107 
108                     executor.shutdownNow();
109 
110                     // Perform one request to get the result
111                     Request request = client.newRequest( url + "?action=result" );
112                     request.header("Cookie", sessionCookie);
113                     ContentResponse response2 = request.send();
114                     assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
115                     String response = response2.getContentAsString();
116                     System.out.println( "get = " + response );
117                     assertEquals(response.trim(), String.valueOf( clientsCount * requestsCount ) );
118                 }
119                 finally
120                 {
121                     client.stop();
122                 }
123             }
124             finally
125             {
126                 server1.stop();
127             }
128         }
129     }
130 
131     public static class Worker implements Runnable
132     {
133         public static int COUNT = 0;
134         
135         private final HttpClient client;
136 
137         private final CyclicBarrier barrier;
138 
139         private final int requestsCount;
140 
141         private final String sessionCookie;
142 
143         private final String url;
144         
145         private final String name;
146 
147 
148         public Worker(CyclicBarrier barrier, HttpClient client, int requestsCount, String sessionCookie, String url)
149         {
150             this.client = client;
151             this.barrier = barrier;
152             this.requestsCount = requestsCount;
153             this.sessionCookie = sessionCookie;
154             this.url = url;
155             this.name = ""+(COUNT++);
156         }
157 
158 
159         public void run()
160         {
161             try
162             {
163                 // Wait for all workers to be ready
164                 barrier.await();
165 
166                 Random random = new Random( System.nanoTime() );
167 
168                 for ( int i = 0; i < requestsCount; ++i )
169                 {
170                     int pauseMsec = random.nextInt(1000);
171 
172                     //wait a random number of milliseconds between requests up to 1 second
173                     if (pauseMsec > 0)
174                     {
175                         Thread.currentThread().sleep(pauseMsec);
176                     }
177                     Request request = client.newRequest(url + "?action=increment");
178                     request.header("Cookie", sessionCookie);
179                     ContentResponse response = request.send();
180                     assertEquals(HttpServletResponse.SC_OK,response.getStatus());
181                 }
182 
183                 // Wait for all workers to be done
184                 barrier.await();
185             }
186             catch ( Exception x )
187             {
188                 throw new RuntimeException( x );
189             }
190         }
191     }
192 
193     public static class TestServlet
194         extends HttpServlet
195     {
196         @Override
197         protected void doGet( HttpServletRequest request, HttpServletResponse response )
198             throws ServletException, IOException
199         {
200             String action = request.getParameter( "action" );
201             if ( "init".equals( action ) )
202             {
203                 HttpSession session = request.getSession( true );
204                 session.setAttribute( "value", 0 );
205             }
206             else if ( "increment".equals( action ) )
207             {
208                 HttpSession session = request.getSession( false );
209                 assertNotNull(session);
210                 synchronized(session)
211                 {
212                     int value = (Integer) session.getAttribute( "value" );
213                     session.setAttribute( "value", value + 1 );
214                 }
215             }
216             else if ( "result".equals( action ) )
217             {
218                 HttpSession session = request.getSession( false );
219                 assertNotNull(session);
220                 Integer value = null;
221                 synchronized (session)
222                 {
223                     value = (Integer) session.getAttribute( "value" );
224                 }
225                 PrintWriter writer = response.getWriter();
226                 writer.println( value );
227                 writer.flush();
228             }
229         }
230     }
231 }