1 /* 2 * Copyright (c) 2005, 2012, 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 /* 25 * @test 26 * @bug 4652922 27 * 28 * @summary synopsis: ReliableLog.update should pad records to 4-byte 29 * boundaries 30 * @author Ann Wollrath 31 * 32 * @run main/othervm/timeout=240 LogTest 33 */ 34 35 import sun.rmi.log.LogHandler; 36 import sun.rmi.log.ReliableLog; 37 import java.io.FileDescriptor; 38 import java.io.FileNotFoundException; 39 import java.io.IOException; 40 import java.io.Serializable; 41 42 public class LogTest { 43 44 private static int crashPoint = 0; 45 private static boolean spansBoundary = false; 46 private static ReliableLog log = null; 47 private static Counter counter = new Counter(); 48 main(String[] args)49 public static void main(String[] args) throws Exception { 50 51 System.err.println("\nRegression test for bug 4652922\n"); 52 53 System.setProperty("sun.rmi.log.class", MyLogFile.class.getName()); 54 //System.setProperty("sun.rmi.log.debug", "true"); 55 56 log = new ReliableLog(".", new TestLogHandler(counter), false); 57 58 writeUpdatesCrashAndRecover(10, 1, false, 10); 59 writeUpdatesCrashAndRecover(10, 1, true, 20); 60 writeUpdatesCrashAndRecover(10, 2, true, 30); 61 writeUpdatesCrashAndRecover(9, 2, false, 40); 62 writeUpdatesCrashAndRecover(9, 3, true, 50); 63 log.close(); 64 } 65 writeUpdatesCrashAndRecover(int updates, int crashValue, boolean spans, int expectedCount)66 private static void writeUpdatesCrashAndRecover(int updates, 67 int crashValue, 68 boolean spans, 69 int expectedCount) 70 throws IOException 71 { 72 /* 73 * Write updates 74 */ 75 System.err.println("\nwrite updates: " + updates); 76 for (int i = 0; i < updates; i++) { 77 counter.increment(); 78 log.update(counter); 79 } 80 81 /* 82 * Crash 83 */ 84 crashPoint = crashValue; 85 spansBoundary = spans; 86 System.err.println("crash during next update on sync #" + 87 crashPoint + 88 " (spansBoundary = " + spansBoundary + ")"); 89 try { 90 System.err.println( 91 "write one update (update record should " + 92 ((counter.value() + 1 == expectedCount) ? "" : "not ") + 93 "be complete)"); 94 counter.increment(); 95 log.update(counter); 96 throw new RuntimeException("failed to reach crashpoint " + 97 crashPoint); 98 } catch (IOException e) { 99 System.err.println("caught IOException; message: " + 100 e.getMessage()); 101 log.close(); 102 } 103 104 /* 105 * Recover 106 */ 107 log = new ReliableLog(".", new TestLogHandler(null), false); 108 try { 109 System.err.println("recover log"); 110 counter = (Counter) log.recover(); 111 System.err.println("recovered counter value: " + counter.value()); 112 if (counter.value() != expectedCount) { 113 throw new RuntimeException("unexpected counter value " + 114 counter.value()); 115 } 116 System.err.println("log recovery successful"); 117 118 } catch (IOException e) { 119 System.err.println("log should recover after crash point"); 120 e.printStackTrace(); 121 throw new RuntimeException( 122 "log should recover after crash point"); 123 } 124 125 } 126 127 private static class Counter implements Serializable { 128 private static long serialVersionUID = 1; 129 private int count = 0; 130 Counter()131 Counter() {} 132 increment()133 int increment() { 134 return ++count; 135 } 136 value()137 int value() { 138 return count; 139 } 140 update(Counter value)141 void update(Counter value) { 142 if (value.value() < count) { 143 throw new IllegalStateException( 144 "bad update (count = " + count + ", value = " + value + ")"); 145 } else { 146 count = value.value(); 147 } 148 } 149 } 150 151 static class TestLogHandler extends LogHandler { 152 153 private final Counter initialState; 154 TestLogHandler(Counter initialState)155 TestLogHandler(Counter initialState) { 156 this.initialState = initialState; 157 } 158 initialSnapshot()159 public Object initialSnapshot() { 160 if (initialState == null) { 161 throw new IllegalStateException( 162 "attempting initialSnapshot with null"); 163 } 164 return initialState; 165 } 166 applyUpdate(Object update, Object state)167 public Object applyUpdate(Object update, Object state) { 168 ((Counter) state).update((Counter) update); 169 return state; 170 } 171 } 172 173 public static class MyLogFile extends ReliableLog.LogFile { 174 MyLogFile(String name, String mode)175 public MyLogFile(String name, String mode) 176 throws FileNotFoundException, IOException 177 { 178 super(name, mode); 179 } 180 sync()181 protected void sync() throws IOException { 182 if (crashPoint != 0) { 183 if (--crashPoint == 0) { 184 throw new IOException("crash point reached"); 185 } 186 } 187 super.sync(); 188 } 189 checkSpansBoundary(long fp)190 protected boolean checkSpansBoundary(long fp) { 191 return 192 crashPoint > 0 ? spansBoundary : super.checkSpansBoundary(fp); 193 } 194 } 195 } 196