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 * @key randomness 29 */ 30 31 import java.util.*; 32 import java.util.concurrent.atomic.*; 33 34 // Usage: java StressTest [threadsFactor [duration]] 35 public class StressTest { 36 static final Locale ROOT_LOCALE = new Locale(""); 37 static final Random rand = new Random(); 38 static final Locale[] locales = { 39 Locale.US, 40 Locale.CHINA, 41 ROOT_LOCALE, 42 Locale.JAPAN, 43 Locale.CANADA, 44 Locale.KOREA 45 }; 46 static final String[] expected = { 47 "U.S.A.", 48 "China", 49 "U.S.A.", 50 "Japan", 51 "U.S.A.", // StressOut_en_CA.properties is empty. 52 "Korea" 53 }; 54 final static long startTime = System.currentTimeMillis(); 55 56 // increment each element when one getBundle call is done. 57 static AtomicIntegerArray counters; 58 static int[] prevCounters; 59 static int intervalForCounterCheck; 60 static AtomicInteger clearCounter = new AtomicInteger(); 61 62 static volatile boolean runrun = true; 63 64 public static void main(String[] args) { 65 int threadsFactor = 2; 66 if (args.length > 0) { 67 threadsFactor = Math.max(2, Integer.parseInt(args[0])); 68 } 69 int duration = 180; 70 if (args.length > 1) { 71 duration = Math.max(5, Integer.parseInt(args[1])); 72 } 73 74 Locale reservedLocale = Locale.getDefault(); 75 try { 76 Locale.setDefault(Locale.US); 77 Thread[] tasks = new Thread[locales.length * threadsFactor]; 78 counters = new AtomicIntegerArray(tasks.length); 79 80 for (int i = 0; i < tasks.length; i++) { 81 tasks[i] = new Thread(new Worker(i)); 82 } 83 for (int i = 0; i < tasks.length; i++) { 84 tasks[i].start(); 85 } 86 87 int nProcessors = Runtime.getRuntime().availableProcessors(); 88 intervalForCounterCheck = Math.max(tasks.length / nProcessors, 1); 89 System.out.printf( 90 "%d processors, intervalForCounterCheck = %d [sec]%n", 91 nProcessors, intervalForCounterCheck); 92 try { 93 for (int i = 0; runrun && i < duration; i++) { 94 Thread.sleep(1000); // 1 second 95 if ((i % intervalForCounterCheck) == 0) { 96 checkCounters(); 97 } 98 } 99 runrun = false; 100 for (int i = 0; i < tasks.length; i++) { 101 tasks[i].join(); 102 } 103 } catch (InterruptedException e) { 104 } 105 106 printCounters(); 107 } finally { 108 // restore the reserved locale 109 Locale.setDefault(reservedLocale); 110 } 111 } 112 113 static void checkCounters() { 114 int length = counters.length(); 115 int[] snapshot = new int[length]; 116 for (int i = 0; i < length; i++) { 117 snapshot[i] = counters.get(i); 118 } 119 120 if (prevCounters == null) { 121 prevCounters = snapshot; 122 return; 123 } 124 125 for (int i = 0; i < length; i++) { 126 if (snapshot[i] > prevCounters[i]) { 127 continue; 128 } 129 System.out.printf( 130 "Warning: Thread #%d hasn't updated its counter for the last %d second(s).%n", 131 i, intervalForCounterCheck); 132 } 133 prevCounters = snapshot; 134 } 135 136 static void printCounters() { 137 long total = 0; 138 int min = Integer.MAX_VALUE; 139 int max = Integer.MIN_VALUE; 140 for (int i = 0; i < counters.length(); i++) { 141 int counter = counters.get(i); 142 total += counter; 143 min = Math.min(min, counter); 144 max = Math.max(max, counter); 145 } 146 System.out.printf("Total: %d calls, min=%d, max=%d, cache cleared %d times%n", 147 total, min, max, clearCounter.get()); 148 } 149 150 static class Worker implements Runnable { 151 final int id; 152 final int index; 153 final Locale locale; 154 final String str; 155 final int max; 156 final boolean cleaner; 157 ResourceBundle.Control control; 158 159 Worker(int i) { 160 id = i; 161 index = i % locales.length; 162 locale = locales[index]; 163 cleaner = locale.equals(ROOT_LOCALE); 164 str = expected[index]; 165 max = rand.nextInt((index + 1) * 500) + 1000; 166 control = new TestControl(max); 167 System.out.println("Worker" + i + ": locale="+locale+", expected="+str+ 168 ", max="+max); 169 } 170 171 public void run() { 172 while (runrun) { 173 ResourceBundle rb = ResourceBundle.getBundle("StressOut", locale, control); 174 counters.incrementAndGet(id); 175 String s = rb.getString("data"); 176 if (!s.equals(str)) { 177 runrun = false; 178 throw new RuntimeException(locale + ": rb.locale=" + rb.getLocale() + 179 ", got " + s + ", expected " + str); 180 } 181 try { 182 Thread.sleep(rand.nextInt(max/500)); 183 } catch (InterruptedException e) { 184 } 185 if (cleaner && (rand.nextInt(10000) == 0)) { 186 //System.out.println("Clearing cache!"); 187 ResourceBundle.clearCache(); 188 clearCounter.incrementAndGet(); 189 } 190 } 191 } 192 193 static class TestControl extends ResourceBundle.Control { 194 int max; 195 196 public List<Locale> getCandidateLocales(String baseName, Locale locale) { 197 List<Locale> list = super.getCandidateLocales(baseName, locale); 198 //System.out.println("Candidate locales=" + list); 199 return list; 200 } 201 public TestControl(int max) { 202 this.max = max; 203 } 204 public long getTimeToLive(String baseName, Locale locale) { 205 // This will set TTL to a random value for each bundle. 206 long ttl = rand.nextInt(max); 207 //System.out.println("TTL: " + baseName + "_" + locale + " for " + ttl); 208 return ttl; 209 } 210 public boolean needsReload(String baseName, Locale locale, 211 String format, ClassLoader loader, 212 ResourceBundle bundle, long loadTime) { 213 //System.out.println("Expired: " + baseName + "_" + locale + "." + format + 214 // " at " + (loadTime-startTime) + ", bundle=" + bundle); 215 return rand.nextBoolean(); 216 } 217 } 218 } 219 }