1 /* 2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 /* 24 * @test 25 * @bug 5102289 26 * @summary Stress test for ResourceBundle.getBundle with ResourceBundle.Control. 27 * @run main/othervm -esa StressTest 2 15 28 */ 29 30 import java.util.*; 31 import java.util.concurrent.atomic.*; 32 33 // Usage: java StressTest [threadsFactor [duration]] 34 public class StressTest { 35 static final Locale ROOT_LOCALE = new Locale(""); 36 static final Random rand = new Random(); 37 static final Locale[] locales = { 38 Locale.US, 39 Locale.CHINA, 40 ROOT_LOCALE, 41 Locale.JAPAN, 42 Locale.CANADA, 43 Locale.KOREA 44 }; 45 static final String[] expected = { 46 "U.S.A.", 47 "China", 48 "U.S.A.", 49 "Japan", 50 "U.S.A.", // StressOut_en_CA.properties is empty. 51 "Korea" 52 }; 53 final static long startTime = System.currentTimeMillis(); 54 55 // increment each element when one getBundle call is done. 56 static AtomicIntegerArray counters; 57 static int[] prevCounters; 58 static int intervalForCounterCheck; 59 static AtomicInteger clearCounter = new AtomicInteger(); 60 61 static volatile boolean runrun = true; 62 63 public static void main(String[] args) { 64 int threadsFactor = 2; 65 if (args.length > 0) { 66 threadsFactor = Math.max(2, Integer.parseInt(args[0])); 67 } 68 int duration = 180; 69 if (args.length > 1) { 70 duration = Math.max(5, Integer.parseInt(args[1])); 71 } 72 73 Locale reservedLocale = Locale.getDefault(); 74 try { 75 Locale.setDefault(Locale.US); 76 Thread[] tasks = new Thread[locales.length * threadsFactor]; 77 counters = new AtomicIntegerArray(tasks.length); 78 79 for (int i = 0; i < tasks.length; i++) { 80 tasks[i] = new Thread(new Worker(i)); 81 } 82 for (int i = 0; i < tasks.length; i++) { 83 tasks[i].start(); 84 } 85 86 int nProcessors = Runtime.getRuntime().availableProcessors(); 87 intervalForCounterCheck = Math.max(tasks.length / nProcessors, 1); 88 System.out.printf( 89 "%d processors, intervalForCounterCheck = %d [sec]%n", 90 nProcessors, intervalForCounterCheck); 91 try { 92 for (int i = 0; runrun && i < duration; i++) { 93 Thread.sleep(1000); // 1 second 94 if ((i % intervalForCounterCheck) == 0) { 95 checkCounters(); 96 } 97 } 98 runrun = false; 99 for (int i = 0; i < tasks.length; i++) { 100 tasks[i].join(); 101 } 102 } catch (InterruptedException e) { 103 } 104 105 printCounters(); 106 } finally { 107 // restore the reserved locale 108 Locale.setDefault(reservedLocale); 109 } 110 } 111 112 static void checkCounters() { 113 int length = counters.length(); 114 int[] snapshot = new int[length]; 115 for (int i = 0; i < length; i++) { 116 snapshot[i] = counters.get(i); 117 } 118 119 if (prevCounters == null) { 120 prevCounters = snapshot; 121 return; 122 } 123 124 for (int i = 0; i < length; i++) { 125 if (snapshot[i] > prevCounters[i]) { 126 continue; 127 } 128 System.out.printf( 129 "Warning: Thread #%d hasn't updated its counter for the last %d second(s).%n", 130 i, intervalForCounterCheck); 131 } 132 prevCounters = snapshot; 133 } 134 135 static void printCounters() { 136 long total = 0; 137 int min = Integer.MAX_VALUE; 138 int max = Integer.MIN_VALUE; 139 for (int i = 0; i < counters.length(); i++) { 140 int counter = counters.get(i); 141 total += counter; 142 min = Math.min(min, counter); 143 max = Math.max(max, counter); 144 } 145 System.out.printf("Total: %d calls, min=%d, max=%d, cache cleared %d times%n", 146 total, min, max, clearCounter.get()); 147 } 148 149 static class Worker implements Runnable { 150 final int id; 151 final int index; 152 final Locale locale; 153 final String str; 154 final int max; 155 final boolean cleaner; 156 ResourceBundle.Control control; 157 158 Worker(int i) { 159 id = i; 160 index = i % locales.length; 161 locale = locales[index]; 162 cleaner = locale.equals(ROOT_LOCALE); 163 str = expected[index]; 164 max = rand.nextInt((index + 1) * 500) + 1000; 165 control = new TestControl(max); 166 System.out.println("Worker" + i + ": locale="+locale+", expected="+str+ 167 ", max="+max); 168 } 169 170 public void run() { 171 while (runrun) { 172 ResourceBundle rb = ResourceBundle.getBundle("StressOut", locale, control); 173 counters.incrementAndGet(id); 174 String s = rb.getString("data"); 175 if (!s.equals(str)) { 176 runrun = false; 177 throw new RuntimeException(locale + ": rb.locale=" + rb.getLocale() + 178 ", got " + s + ", expected " + str); 179 } 180 try { 181 Thread.sleep(rand.nextInt(max/500)); 182 } catch (InterruptedException e) { 183 } 184 if (cleaner && (rand.nextInt(10000) == 0)) { 185 //System.out.println("Clearing cache!"); 186 ResourceBundle.clearCache(); 187 clearCounter.incrementAndGet(); 188 } 189 } 190 } 191 192 static class TestControl extends ResourceBundle.Control { 193 int max; 194 195 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 196 List<Locale> list = super.getCandidateLocales(baseName, locale); 197 //System.out.println("Candidate locales=" + list); 198 return list; 199 } 200 public TestControl(int max) { 201 this.max = max; 202 } 203 public long getTimeToLive(String baseName, Locale locale) { 204 // This will set TTL to a random value for each bundle. 205 long ttl = rand.nextInt(max); 206 //System.out.println("TTL: " + baseName + "_" + locale + " for " + ttl); 207 return ttl; 208 } 209 public boolean needsReload(String baseName, Locale locale, 210 String format, ClassLoader loader, 211 ResourceBundle bundle, long loadTime) { 212 //System.out.println("Expired: " + baseName + "_" + locale + "." + format + 213 // " at " + (loadTime-startTime) + ", bundle=" + bundle); 214 return rand.nextBoolean(); 215 } 216 } 217 } 218 }