/*
* Copyright (c) 2005, 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 4652922
*
* @summary synopsis: ReliableLog.update should pad records to 4-byte
* boundaries
* @author Ann Wollrath
*
* @run main/othervm/timeout=240 LogTest
*/
import sun.rmi.log.LogHandler;
import sun.rmi.log.ReliableLog;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
public class LogTest {
private static int crashPoint = 0;
private static boolean spansBoundary = false;
private static ReliableLog log = null;
private static Counter counter = new Counter();
public static void main(String[] args) throws Exception {
System.err.println("\nRegression test for bug 4652922\n");
System.setProperty("sun.rmi.log.class", MyLogFile.class.getName());
//System.setProperty("sun.rmi.log.debug", "true");
log = new ReliableLog(".", new TestLogHandler(counter), false);
writeUpdatesCrashAndRecover(10, 1, false, 10);
writeUpdatesCrashAndRecover(10, 1, true, 20);
writeUpdatesCrashAndRecover(10, 2, true, 30);
writeUpdatesCrashAndRecover(9, 2, false, 40);
writeUpdatesCrashAndRecover(9, 3, true, 50);
log.close();
}
private static void writeUpdatesCrashAndRecover(int updates,
int crashValue,
boolean spans,
int expectedCount)
throws IOException
{
/*
* Write updates
*/
System.err.println("\nwrite updates: " + updates);
for (int i = 0; i < updates; i++) {
counter.increment();
log.update(counter);
}
/*
* Crash
*/
crashPoint = crashValue;
spansBoundary = spans;
System.err.println("crash during next update on sync #" +
crashPoint +
" (spansBoundary = " + spansBoundary + ")");
try {
System.err.println(
"write one update (update record should " +
((counter.value() + 1 == expectedCount) ? "" : "not ") +
"be complete)");
counter.increment();
log.update(counter);
throw new RuntimeException("failed to reach crashpoint " +
crashPoint);
} catch (IOException e) {
System.err.println("caught IOException; message: " +
e.getMessage());
log.close();
}
/*
* Recover
*/
log = new ReliableLog(".", new TestLogHandler(null), false);
try {
System.err.println("recover log");
counter = (Counter) log.recover();
System.err.println("recovered counter value: " + counter.value());
if (counter.value() != expectedCount) {
throw new RuntimeException("unexpected counter value " +
counter.value());
}
System.err.println("log recovery successful");
} catch (IOException e) {
System.err.println("log should recover after crash point");
e.printStackTrace();
throw new RuntimeException(
"log should recover after crash point");
}
}
private static class Counter implements Serializable {
private static long serialVersionUID = 1;
private int count = 0;
Counter() {}
int increment() {
return ++count;
}
int value() {
return count;
}
void update(Counter value) {
if (value.value() < count) {
throw new IllegalStateException(
"bad update (count = " + count + ", value = " + value + ")");
} else {
count = value.value();
}
}
}
static class TestLogHandler extends LogHandler {
private final Counter initialState;
TestLogHandler(Counter initialState) {
this.initialState = initialState;
}
public Object initialSnapshot() {
if (initialState == null) {
throw new IllegalStateException(
"attempting initialSnapshot with null");
}
return initialState;
}
public Object applyUpdate(Object update, Object state) {
((Counter) state).update((Counter) update);
return state;
}
}
public static class MyLogFile extends ReliableLog.LogFile {
public MyLogFile(String name, String mode)
throws FileNotFoundException, IOException
{
super(name, mode);
}
protected void sync() throws IOException {
if (crashPoint != 0) {
if (--crashPoint == 0) {
throw new IOException("crash point reached");
}
}
super.sync();
}
protected boolean checkSpansBoundary(long fp) {
return
crashPoint > 0 ? spansBoundary : super.checkSpansBoundary(fp);
}
}
}