/* * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 5102289 * @summary Stress test for ResourceBundle.getBundle with ResourceBundle.Control. * @run main/othervm -esa StressTest 2 15 */ import java.util.*; import java.util.concurrent.atomic.*; // Usage: java StressTest [threadsFactor [duration]] public class StressTest { static final Locale ROOT_LOCALE = new Locale(""); static final Random rand = new Random(); static final Locale[] locales = { Locale.US, Locale.CHINA, ROOT_LOCALE, Locale.JAPAN, Locale.CANADA, Locale.KOREA }; static final String[] expected = { "U.S.A.", "China", "U.S.A.", "Japan", "U.S.A.", // StressOut_en_CA.properties is empty. "Korea" }; final static long startTime = System.currentTimeMillis(); // increment each element when one getBundle call is done. static AtomicIntegerArray counters; static int[] prevCounters; static int intervalForCounterCheck; static AtomicInteger clearCounter = new AtomicInteger(); static volatile boolean runrun = true; public static void main(String[] args) { int threadsFactor = 2; if (args.length > 0) { threadsFactor = Math.max(2, Integer.parseInt(args[0])); } int duration = 180; if (args.length > 1) { duration = Math.max(5, Integer.parseInt(args[1])); } Locale reservedLocale = Locale.getDefault(); try { Locale.setDefault(Locale.US); Thread[] tasks = new Thread[locales.length * threadsFactor]; counters = new AtomicIntegerArray(tasks.length); for (int i = 0; i < tasks.length; i++) { tasks[i] = new Thread(new Worker(i)); } for (int i = 0; i < tasks.length; i++) { tasks[i].start(); } int nProcessors = Runtime.getRuntime().availableProcessors(); intervalForCounterCheck = Math.max(tasks.length / nProcessors, 1); System.out.printf( "%d processors, intervalForCounterCheck = %d [sec]%n", nProcessors, intervalForCounterCheck); try { for (int i = 0; runrun && i < duration; i++) { Thread.sleep(1000); // 1 second if ((i % intervalForCounterCheck) == 0) { checkCounters(); } } runrun = false; for (int i = 0; i < tasks.length; i++) { tasks[i].join(); } } catch (InterruptedException e) { } printCounters(); } finally { // restore the reserved locale Locale.setDefault(reservedLocale); } } static void checkCounters() { int length = counters.length(); int[] snapshot = new int[length]; for (int i = 0; i < length; i++) { snapshot[i] = counters.get(i); } if (prevCounters == null) { prevCounters = snapshot; return; } for (int i = 0; i < length; i++) { if (snapshot[i] > prevCounters[i]) { continue; } System.out.printf( "Warning: Thread #%d hasn't updated its counter for the last %d second(s).%n", i, intervalForCounterCheck); } prevCounters = snapshot; } static void printCounters() { long total = 0; int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; for (int i = 0; i < counters.length(); i++) { int counter = counters.get(i); total += counter; min = Math.min(min, counter); max = Math.max(max, counter); } System.out.printf("Total: %d calls, min=%d, max=%d, cache cleared %d times%n", total, min, max, clearCounter.get()); } static class Worker implements Runnable { final int id; final int index; final Locale locale; final String str; final int max; final boolean cleaner; ResourceBundle.Control control; Worker(int i) { id = i; index = i % locales.length; locale = locales[index]; cleaner = locale.equals(ROOT_LOCALE); str = expected[index]; max = rand.nextInt((index + 1) * 500) + 1000; control = new TestControl(max); System.out.println("Worker" + i + ": locale="+locale+", expected="+str+ ", max="+max); } public void run() { while (runrun) { ResourceBundle rb = ResourceBundle.getBundle("StressOut", locale, control); counters.incrementAndGet(id); String s = rb.getString("data"); if (!s.equals(str)) { runrun = false; throw new RuntimeException(locale + ": rb.locale=" + rb.getLocale() + ", got " + s + ", expected " + str); } try { Thread.sleep(rand.nextInt(max/500)); } catch (InterruptedException e) { } if (cleaner && (rand.nextInt(10000) == 0)) { //System.out.println("Clearing cache!"); ResourceBundle.clearCache(); clearCounter.incrementAndGet(); } } } static class TestControl extends ResourceBundle.Control { int max; public List<Locale> getCandidateLocales(String baseName, Locale locale) { List<Locale> list = super.getCandidateLocales(baseName, locale); //System.out.println("Candidate locales=" + list); return list; } public TestControl(int max) { this.max = max; } public long getTimeToLive(String baseName, Locale locale) { // This will set TTL to a random value for each bundle. long ttl = rand.nextInt(max); //System.out.println("TTL: " + baseName + "_" + locale + " for " + ttl); return ttl; } public boolean needsReload(String baseName, Locale locale, String format, ClassLoader loader, ResourceBundle bundle, long loadTime) { //System.out.println("Expired: " + baseName + "_" + locale + "." + format + // " at " + (loadTime-startTime) + ", bundle=" + bundle); return rand.nextBoolean(); } } } }