View Javadoc
1   package org.apache.commons.jcs3;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.List;
23  import java.util.concurrent.CopyOnWriteArrayList;
24  import java.util.concurrent.atomic.AtomicInteger;
25  
26  import org.apache.commons.jcs3.access.GroupCacheAccess;
27  import org.apache.commons.jcs3.access.exception.CacheException;
28  
29  import junit.framework.TestCase;
30  
31  /**
32   * Test Case for JCS-73, modeled after the Groovy code by Alexander Kleymenov
33   */
34  public class JCSConcurrentCacheAccessUnitTest extends TestCase
35  {
36      private final static int THREADS = 20;
37      private final static int LOOPS = 10000;
38  
39      /**
40       * the cache instance
41       */
42      protected GroupCacheAccess<Integer, String> cache;
43  
44      /**
45       * the group name
46       */
47      protected String group = "group";
48  
49      /**
50       * the error count
51       */
52      protected AtomicInteger errcount;
53  
54      /**
55       * Collect all value mismatches
56       */
57      protected List<String> valueMismatchList;
58  
59      @Override
60  	protected void setUp() throws Exception
61  	{
62          super.setUp();
63          JCS.setConfigFilename( "/TestJCS-73.ccf" );
64          cache = JCS.getGroupCacheInstance( "cache" );
65          errcount = new AtomicInteger(0);
66          valueMismatchList = new CopyOnWriteArrayList<>();
67  	}
68  
69      @Override
70      protected void tearDown()
71          throws Exception
72      {
73          super.tearDown();
74          cache.clear();
75          cache.dispose();
76      }
77  
78      /**
79       * Worker thread
80       */
81      protected class Worker extends Thread
82      {
83      	@Override
84  		public void run()
85  		{
86  			final String name = getName();
87  
88  			for (int idx = 0; idx < LOOPS; idx++)
89  			{
90  				if (idx > 0)
91  				{
92  					// get previously stored value
93  		            String res = cache.getFromGroup(Integer.valueOf(idx-1), group);
94  
95  		            if (res == null)
96  		            {
97  		                // null value got inspite of the fact it was placed in cache!
98  		                System.out.println("ERROR: for " + idx + " in " + name);
99  		                errcount.incrementAndGet();
100 
101 		                // try to get the value again:
102 		                int n = 5;
103 		                while (n-- > 0)
104 		                {
105 		                    res = cache.getFromGroup(Integer.valueOf(idx-1), group);
106 		                    if (res != null)
107 		                    {
108 		                        // the value finally appeared in cache
109 		                    	System.out.println("ERROR FIXED for " + idx + ": " + res + " " + name);
110 		                    	errcount.decrementAndGet();
111 		                        break;
112 		                    }
113 
114 		                    System.out.println("ERROR STILL PERSISTS for " + idx + " in " + name);
115 		                    try
116 		                    {
117 								Thread.sleep(1000);
118 							}
119 		                    catch (final InterruptedException e)
120 							{
121 								// continue
122 							}
123 		                }
124 		            }
125 
126 		            if (!String.valueOf(idx-1).equals(res))
127 		            {
128 		                valueMismatchList.add(String.format("Values do not match: %s - %s", String.valueOf(idx-1), res));
129 		            }
130 				}
131 
132 				 // put value in the cache
133 		        try
134 		        {
135 					cache.putInGroup(Integer.valueOf(idx), group, String.valueOf(idx));
136 				}
137 		        catch (final CacheException e)
138 		        {
139 		        	// continue
140 				}
141 
142 //		        if ((idx % 1000) == 0)
143 //		        {
144 //		        	System.out.println(name + " " + idx);
145 //		        }
146 			}
147 
148 		}
149     }
150 
151 	/**
152      *
153      * @throws Exception
154      */
155     public void testConcurrentAccess()
156         throws Exception
157     {
158     	final Worker[] worker = new Worker[THREADS];
159 
160         for (int i = 0; i < THREADS; i++)
161         {
162         	worker[i] = new Worker();
163         	worker[i].start();
164         }
165 
166         for (int i = 0; i < THREADS; i++)
167         {
168         	worker[i].join();
169         }
170 
171         assertEquals("Error count should be 0",  0, errcount.intValue());
172         for (final String msg : valueMismatchList)
173         {
174             System.out.println(msg);
175         }
176         assertEquals("Value mismatch count should be 0",  0, valueMismatchList.size());
177     }
178 
179 }