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