提交 5459085f 编写于 作者: O olagneau

7144861: speed up RMI activation tests

Reviewed-by: alanb, smarks, dholmes, dmocek
上级 f0fa3444
...@@ -53,12 +53,9 @@ public class CheckUsage { ...@@ -53,12 +53,9 @@ public class CheckUsage {
rmidVM.start(); rmidVM.start();
// wait for registry exit // wait for registry exit
int rmidVMExitStatus = rmidVM.getVM().waitFor();
System.err.println("rmid exited with status: " + System.err.println("rmid exited with status: " +
rmidVM.getVM().waitFor()); rmidVMExitStatus);
try {
Thread.sleep(7000);
} catch (InterruptedException ie) {
}
String usage = new String(berr.toByteArray()); String usage = new String(berr.toByteArray());
......
...@@ -63,19 +63,30 @@ public class ActivationLibrary { ...@@ -63,19 +63,30 @@ public class ActivationLibrary {
*/ */
public static void deactivate(Remote remote, public static void deactivate(Remote remote,
ActivationID id) { ActivationID id) {
for (int i = 0; i < 5; i ++) { // We do as much as 50 deactivation trials, each separated by
// at least 100 milliseconds sleep time (max sleep time of 5 secs).
final long deactivateSleepTime = 100;
for (int i = 0; i < 50; i ++) {
try { try {
if (Activatable.inactive(id) == true) { if (Activatable.inactive(id) == true) {
mesg("inactive successful"); mesg("inactive successful");
return; return;
} else { } else {
Thread.sleep(1000); mesg("inactive trial failed. Sleeping " +
deactivateSleepTime +
" milliseconds before next trial");
Thread.sleep(deactivateSleepTime);
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
continue; Thread.currentThread().interrupt();
mesg("Thread interrupted while trying to deactivate activatable. Exiting deactivation");
return;
} catch (Exception e) { } catch (Exception e) {
try { try {
// forcibly unexport the object // forcibly unexport the object
mesg("Unexpected exception. Have to forcibly unexport the object." +
" Exception was :");
e.printStackTrace();
Activatable.unexportObject(remote, true); Activatable.unexportObject(remote, true);
} catch (NoSuchObjectException ex) { } catch (NoSuchObjectException ex) {
} }
...@@ -99,37 +110,61 @@ public class ActivationLibrary { ...@@ -99,37 +110,61 @@ public class ActivationLibrary {
* activation system. * activation system.
*/ */
public static boolean rmidRunning(int port) { public static boolean rmidRunning(int port) {
int allowedNotReady = 10; int allowedNotReady = 50;
int connectionRefusedExceptions = 0; int connectionRefusedExceptions = 0;
for (int i = 0; i < 15 ; i++) { /* We wait as much as a total of 7.5 secs trying to see Rmid running.
* We do this by pausing steps of 100 milliseconds (so up to 75 steps),
* right after trying to lookup and find RMID running in the other vm.
*/
final long rmidWaitingStepTime = 100;
for (int i = 0; i <= 74; i++) {
try { try {
Thread.sleep(500);
LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME); LocateRegistry.getRegistry(port).lookup(SYSTEM_NAME);
mesg("Activation System available after " +
(i * rmidWaitingStepTime) + " milliseconds");
return true; return true;
} catch (java.rmi.ConnectException e) { } catch (java.rmi.ConnectException e) {
// ignore connect exceptions until we decide rmid is not up mesg("Remote connection refused after " +
(i * rmidWaitingStepTime) + " milliseconds");
// ignore connect exceptions until we decide rmid is not up
if ((connectionRefusedExceptions ++) >= allowedNotReady) { if ((connectionRefusedExceptions ++) >= allowedNotReady) {
return false; return false;
} }
} catch (NotBoundException e) { } catch (java.rmi.NoSuchObjectException nsoe) {
/* Activation System still unavailable.
* Ignore this since we are just waiting for its availibility.
* Just signal unavailibility.
*/
mesg("Activation System still unavailable after more than " +
(i * rmidWaitingStepTime) + " milliseconds");
} catch (NotBoundException e) {
return false; return false;
} catch (Exception e) { } catch (Exception e) {
// print out other types of exceptions as an FYI. /* print out other types of exceptions as an FYI.
// test should not fail as rmid is likely to be in an * test should not fail as rmid is likely to be in an
// undetermined state at this point. * undetermined state at this point.
*/
mesg("caught an exception trying to" + mesg("caught an exception trying to" +
" start rmid, last exception was: " + " start rmid, last exception was: " +
e.getMessage()); e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
// Waiting for another 100 milliseconds.
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mesg("Thread interrupted while checking if Activation System is running. Exiting check");
return false;
}
} }
return false; return false;
} }
......
...@@ -36,7 +36,6 @@ import java.util.StringTokenizer; ...@@ -36,7 +36,6 @@ import java.util.StringTokenizer;
*/ */
public class JavaVM { public class JavaVM {
// need to
protected Process vm = null; protected Process vm = null;
private String classname = ""; private String classname = "";
...@@ -46,6 +45,10 @@ public class JavaVM { ...@@ -46,6 +45,10 @@ public class JavaVM {
private OutputStream errorStream = System.err; private OutputStream errorStream = System.err;
private String policyFileName = null; private String policyFileName = null;
// This is used to shorten waiting time at startup.
private volatile boolean started = false;
private boolean forcesOutput = true; // default behavior
private static void mesg(Object mesg) { private static void mesg(Object mesg) {
System.err.println("JAVAVM: " + mesg.toString()); System.err.println("JAVAVM: " + mesg.toString());
} }
...@@ -79,6 +82,25 @@ public class JavaVM { ...@@ -79,6 +82,25 @@ public class JavaVM {
this.errorStream = err; this.errorStream = err;
} }
/* This constructor will instantiate a JavaVM object for which caller
* can ask for forcing initial version output on child vm process
* (if forcesVersionOutput is true), or letting the started vm behave freely
* (when forcesVersionOutput is false).
*/
public JavaVM(String classname,
String options, String args,
OutputStream out, OutputStream err,
boolean forcesVersionOutput) {
this(classname, options, args, out, err);
this.forcesOutput = forcesVersionOutput;
}
public void setStarted() {
started = true;
}
// Prepends passed opts array to current options
public void addOptions(String[] opts) { public void addOptions(String[] opts) {
String newOpts = ""; String newOpts = "";
for (int i = 0 ; i < opts.length ; i ++) { for (int i = 0 ; i < opts.length ; i ++) {
...@@ -87,6 +109,8 @@ public class JavaVM { ...@@ -87,6 +109,8 @@ public class JavaVM {
newOpts += " "; newOpts += " ";
options = newOpts + options; options = newOpts + options;
} }
// Prepends passed arguments array to current args
public void addArguments(String[] arguments) { public void addArguments(String[] arguments) {
String newArgs = ""; String newArgs = "";
for (int i = 0 ; i < arguments.length ; i ++) { for (int i = 0 ; i < arguments.length ; i ++) {
...@@ -127,6 +151,18 @@ public class JavaVM { ...@@ -127,6 +151,18 @@ public class JavaVM {
addOptions(new String[] { getCodeCoverageOptions() }); addOptions(new String[] { getCodeCoverageOptions() });
/*
* If forcesOutput is true :
* We force the new starting vm to output something so that we can know
* when it is effectively started by redirecting standard output through
* the next StreamPipe call (the vm is considered started when a first
* output has been streamed out).
* We do this by prepnding a "-showversion" option in the command line.
*/
if (forcesOutput) {
addOptions(new String[] {"-showversion"});
}
StringTokenizer optionsTokenizer = new StringTokenizer(options); StringTokenizer optionsTokenizer = new StringTokenizer(options);
StringTokenizer argsTokenizer = new StringTokenizer(args); StringTokenizer argsTokenizer = new StringTokenizer(args);
int optionsCount = optionsTokenizer.countTokens(); int optionsCount = optionsTokenizer.countTokens();
...@@ -150,15 +186,43 @@ public class JavaVM { ...@@ -150,15 +186,43 @@ public class JavaVM {
vm = Runtime.getRuntime().exec(javaCommand); vm = Runtime.getRuntime().exec(javaCommand);
/* output from the execed process may optionally be captured. */ /* output from the execed process may optionally be captured. */
StreamPipe.plugTogether(vm.getInputStream(), this.outputStream); StreamPipe.plugTogether(this, vm.getInputStream(), this.outputStream);
StreamPipe.plugTogether(vm.getErrorStream(), this.errorStream); StreamPipe.plugTogether(this, vm.getErrorStream(), this.errorStream);
try { try {
Thread.sleep(2000); if (forcesOutput) {
} catch (Exception ignore) { // Wait distant vm to start, by using waiting time slices of 100 ms.
// Wait at most for 2secs, after it considers the vm to be started.
final long vmStartSleepTime = 100;
final int maxTrials = 20;
int numTrials = 0;
while (!started && numTrials < maxTrials) {
numTrials++;
Thread.sleep(vmStartSleepTime);
}
// Outputs running status of distant vm
String message =
"after " + (numTrials * vmStartSleepTime) + " milliseconds";
if (started) {
mesg("distant vm process running, " + message);
}
else {
mesg("unknown running status of distant vm process, " + message);
}
}
else {
// Since we have no way to know if the distant vm is started,
// we just consider the vm to be started after a 2secs waiting time.
Thread.sleep(2000);
mesg("distant vm considered to be started after a waiting time of 2 secs");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mesg("Thread interrupted while checking if distant vm is started. Giving up check.");
mesg("Distant vm state unknown");
return;
} }
mesg("finished starting vm.");
} }
public void destroy() { public void destroy() {
......
...@@ -218,20 +218,30 @@ public class RMID extends JavaVM { ...@@ -218,20 +218,30 @@ public class RMID extends JavaVM {
} catch (NumberFormatException ignore) {} } catch (NumberFormatException ignore) {}
waitTime = waitTime * slopFactor; waitTime = waitTime * slopFactor;
// give rmid time to come up // We check several times (as many as provides passed waitTime) to
// see if Rmid is currently running. Waiting steps last 100 msecs.
final long rmidStartSleepTime = 100;
do { do {
// Sleeping for another rmidStartSleepTime time slice.
try { try {
Thread.sleep(Math.min(waitTime, 10000)); Thread.sleep(Math.min(waitTime, rmidStartSleepTime));
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
mesg("Thread interrupted while checking for start of Activation System. Giving up check.");
mesg("Activation System state unknown");
return;
} }
waitTime -= 10000; waitTime -= rmidStartSleepTime;
// is rmid present? // Checking if rmid is present
if (ActivationLibrary.rmidRunning(port)) { if (ActivationLibrary.rmidRunning(port)) {
mesg("finished starting rmid."); mesg("finished starting rmid.");
return; return;
} }
else {
mesg("rmid still not started");
}
} while (waitTime > 0); } while (waitTime > 0);
TestLibrary.bomb("start rmid failed... giving up", null); TestLibrary.bomb("start rmid failed... giving up", null);
} }
...@@ -264,6 +274,8 @@ public class RMID extends JavaVM { ...@@ -264,6 +274,8 @@ public class RMID extends JavaVM {
port + port +
"/java.rmi.activation.ActivationSystem"); "/java.rmi.activation.ActivationSystem");
mesg("obtained a reference to the activation system"); mesg("obtained a reference to the activation system");
} catch (RemoteException re) {
mesg("could not contact registry while trying to shutdown activation system");
} catch (java.net.MalformedURLException mue) { } catch (java.net.MalformedURLException mue) {
} }
...@@ -272,19 +284,14 @@ public class RMID extends JavaVM { ...@@ -272,19 +284,14 @@ public class RMID extends JavaVM {
} }
system.shutdown(); system.shutdown();
} catch (RemoteException re) {
mesg("shutting down the activation daemon failed");
} catch (Exception e) { } catch (Exception e) {
mesg("caught exception trying to shutdown rmid"); mesg("caught exception trying to shutdown rmid");
mesg(e.getMessage()); mesg(e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
try {
// wait for the shutdown to happen
Thread.sleep(5000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
mesg("testlibrary finished shutting down rmid"); mesg("testlibrary finished shutting down rmid");
} }
...@@ -301,18 +308,47 @@ public class RMID extends JavaVM { ...@@ -301,18 +308,47 @@ public class RMID extends JavaVM {
if (vm != null) { if (vm != null) {
try { try {
// destroy rmid if it is still running... /* Waiting for distant RMID process to shutdown.
try { * Waiting is bounded at a hardcoded max of 60 secs (1 min).
vm.exitValue(); * Waiting by steps of 200 msecs, thus at most 300 such attempts
mesg("rmid exited on shutdown request"); * for termination of distant RMID process. If process is not
} catch (IllegalThreadStateException illegal) { * known to be terminated properly after that time,
mesg("Had to destroy RMID's process " + * we give up for a gracefull termination, and thus go for
"using Process.destroy()"); * forcibly destroying the process.
*/
boolean vmEnded = false;
int waitingTrials = 0;
final int maxTrials = 300;
final long vmProcessEndWaitInterval = 200;
int vmExitValue;
do {
try {
Thread.sleep(vmProcessEndWaitInterval);
waitingTrials++;
vmExitValue = vm.exitValue();
mesg("rmid exited on shutdown request");
vmEnded = true;
} catch (IllegalThreadStateException illegal) {
mesg("RMID's process still not terminated after more than " +
(waitingTrials * vmProcessEndWaitInterval) + " milliseconds");
}
}
while (!vmEnded &&
(waitingTrials < maxTrials));
if (waitingTrials >= maxTrials) {
mesg("RMID's process still not terminated after more than " +
(waitingTrials * vmProcessEndWaitInterval) + " milliseconds." +
"Givinp up gracefull termination...");
mesg("destroying RMID's process using Process.destroy()");
super.destroy(); super.destroy();
} }
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
mesg("Thread interrupted while checking for termination of distant rmid vm. Giving up check.");
} catch (Exception e) { } catch (Exception e) {
mesg("caught exception trying to destroy rmid: " + mesg("caught unexpected exception trying to destroy rmid: " +
e.getMessage()); e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
......
...@@ -35,46 +35,89 @@ public class StreamPipe extends Thread { ...@@ -35,46 +35,89 @@ public class StreamPipe extends Thread {
private InputStream in; private InputStream in;
private OutputStream out; private OutputStream out;
private String preamble; private String preamble;
private JavaVM javaVM;
private static Object lock = new Object(); private static Object lock = new Object();
private static int count = 0; private static int count = 0;
public StreamPipe(InputStream in, OutputStream out, String name) {
/* StreamPipe constructor : should only be called by plugTogether() method !!
* If passed vm is not null :
* - This is StreamPipe usage when streams to pipe come from a given
* vm (JavaVM) process (the vm process must be started with a prefixed
* "-showversion" option to be able to determine as soon as possible when
* the vm process is started through the redirection of the streams).
* There must be a close connection between the StreamPipe instance and
* the JavaVM object on which a start() call has been done.
* run() method will flag distant JavaVM as started.
* If passed vm is null :
* - We don't have control on the process which we want to redirect the passed
* streams.
* run() method will ignore distant process.
*/
private StreamPipe(JavaVM vm, InputStream in, OutputStream out, String name) {
super(name); super(name);
this.in = in; this.in = in;
this.out = out; this.out = out;
this.preamble = "# "; this.preamble = "# ";
this.javaVM = vm;
}
// Install redirection of passed InputStream and OutputStream from passed JavaVM
// to this vm standard output and input streams.
public static void plugTogether(JavaVM vm, InputStream in, OutputStream out) {
String name = null;
synchronized (lock) {
name = "TestLibrary: StreamPipe-" + (count ++ );
}
Thread pipe = new StreamPipe(vm, in, out, name);
pipe.setDaemon(true);
pipe.start();
}
/* Redirects the InputStream and OutputStream passed by caller to this
* vm standard output and input streams.
* (we just have to use fully parametered plugTogether() call with a null
* JavaVM input to do this).
*/
public static void plugTogether(InputStream in, OutputStream out) {
plugTogether(null, in, out);
} }
// Starts redirection of streams.
public void run() { public void run() {
BufferedReader r = new BufferedReader(new InputStreamReader(in), 1); BufferedReader r = new BufferedReader(new InputStreamReader(in), 1);
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out)); BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out));
byte[] buf = new byte[256]; byte[] buf = new byte[256];
boolean bol = true; // beginning-of-line
int count;
try { try {
String line; String line;
while ((line = r.readLine()) != null) {
/* This is to check that the distant vm has started,
* if such a vm has been provided at construction :
* - As soon as we can read something from r BufferedReader,
* that means the distant vm is already started.
* Thus we signal associated JavaVM object that it is now started.
*/
if (((line = r.readLine()) != null) &&
(javaVM != null)) {
javaVM.setStarted();
}
// Redirects r on w.
while (line != null) {
w.write(preamble); w.write(preamble);
w.write(line); w.write(line);
w.newLine(); w.newLine();
w.flush(); w.flush();
line = r.readLine();
} }
} catch (IOException e) { } catch (IOException e) {
System.err.println("*** IOException in StreamPipe.run:"); System.err.println("*** IOException in StreamPipe.run:");
e.printStackTrace(); e.printStackTrace();
} }
} }
public static void plugTogether(InputStream in, OutputStream out) {
String name = null;
synchronized (lock) {
name = "TestLibrary: StreamPipe-" + (count ++ );
}
Thread pipe = new StreamPipe(in, out, name);
pipe.setDaemon(true);
pipe.start();
}
} }
...@@ -60,9 +60,12 @@ public class NoConsoleOutput { ...@@ -60,9 +60,12 @@ public class NoConsoleOutput {
File.separatorChar + "logging.properties"; File.separatorChar + "logging.properties";
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayOutputStream err = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream();
// We instantiate a JavaVM that should not produce any console output
// (neither on standard output, nor on standard err streams).
JavaVM vm = new JavaVM(DoRMIStuff.class.getName(), JavaVM vm = new JavaVM(DoRMIStuff.class.getName(),
"-Djava.util.logging.config.file=" + loggingPropertiesFile, "-Djava.util.logging.config.file=" + loggingPropertiesFile,
"", out, err); "", out, err, false);
vm.start(); vm.start();
vm.getVM().waitFor(); vm.getVM().waitFor();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册