1/* 2 * Copyright (c) 1998, 2002, 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 * @summary sanity test for log sudden-death and recovery 26 * @run ignore Requires special hooks in ReliableLog not yet putback. 27 */ 28 29/* The ReliableLog uses three filenames and renaming to effect atomic 30 * versionFile updates. First, a newVersionFile (an intention list) 31 * is written. Next, the current versionFile is renamed to an 32 * oldVersionFile (an undo list). Finally, the newVersionFile is 33 * renamed to the current versionFile, and the undo list is discarded. 34 * If the current version file does not exist on restart, then 35 * stability can always be restored by reading the oldVersionFile. 36 * 37 * This test uses little conditional bombs. When a switch is flipped 38 * in ReliableLog, the code will abort with an InternalError at a 39 * particular point. We then pretend to have come up from scratch and 40 * recover from the bombed situation. 41 */ 42 43import java.io.File; 44import java.io.IOException; 45import java.io.PrintStream; 46import java.io.Serializable; 47import sun.rmi.log.LogHandler; 48import sun.rmi.log.ReliableLog; 49 50//import javasoft.sqe.harness.Status; 51//import javasoft.sqe.harness.Test; 52 53public class Recovery 54 extends LogHandler 55 implements Serializable //, Test 56{ 57 static private final String dir = "./recovery_tmp"; 58 59 static public void main (String[] argv) 60 { 61 Recovery test = new Recovery(); 62 //Status status = test.run (argv, System.err, System.out); 63 //status.exit(); 64 test.run (argv, System.err, System.out); 65 } 66 67 //public Status run (String argv[], PrintStream log, PrintStream out) 68 public void run (String argv[], PrintStream lg, PrintStream out) 69 { 70 try { 71 int size; 72 int deathpoint; 73 for (size = 1; size < 256; size *= 2) { 74 for (deathpoint = 0; deathpoint <= 8; deathpoint++) { 75 // Trash the log directory 76 try { 77 (new File(dir,"Version_Number")).delete(); 78 } catch (Exception e) { 79 } 80 try { 81 (new File(dir,"New_Version_Number")).delete(); 82 } catch (Exception e) { 83 } 84 try { 85 (new File(dir,"Old_Version_Number")).delete(); 86 } catch (Exception e) { 87 } 88 89 Recovery handler = new Recovery(); 90 ReliableLog log; 91 if (size == 4 && deathpoint == 6) { 92 Runtime.getRuntime().traceMethodCalls(true); 93 } 94 log = new ReliableLog(dir, handler); 95 if (size == 4 && deathpoint == 6) { 96 Runtime.getRuntime().traceMethodCalls(false); 97 } 98 99 // Generate a number of updates (size - 1) until failing 100 int i; 101 StringBuffer writ = new StringBuffer(); 102 char[] u = new char[1]; 103 for (i = 1; i < size; i++) { 104 u[0] = (char)(64 + (i % 26)); 105 String update = new String(u); 106 handler.basicUpdate(update); 107 log.update(update, true); 108 writ.append(update); 109 } 110 111 // Fail 112 String f = ("FALL" + deathpoint); 113 boolean failed_as_desired = false; 114 try { 115 ReliableLog.fallOverPoint = deathpoint; 116 handler.basicUpdate(f); 117 log.update(f, true); 118 log.snapshot(handler); 119 } catch (InternalError e) { 120 if (!e.getMessage().equals(f)) 121 throw e; // oops, not ours 122 failed_as_desired = true; 123 } finally { 124 ReliableLog.fallOverPoint = 0; 125 try { 126 log.close(); 127 } catch (IOException ign) { 128 } 129 } 130 131 // deathpoint == 0 means that there is no deathpoint and we are testing 132 // undisastered behaviour. 133 if (!failed_as_desired && deathpoint != 0) { 134 System.err.println ("sun.rmi.log.ReliableLog is not instrumented for" + 135 " this test; test skipped"); 136 return; 137 } 138 139 // Now try to recover. 140 Recovery laz = new Recovery(); 141 ReliableLog carbon = new ReliableLog(dir, laz); 142 Recovery thingy; 143 thingy = (Recovery)carbon.recover(); 144 try { 145 carbon.close(); 146 } catch (IOException ign) { 147 } 148 149 // Recovered thingy must be equal to writ or to writ + f, but nothing 150 // else (or in between). 151 String recovered = thingy.contents; 152 String sacr = writ.toString(); 153 if (recovered.length() == sacr.length() 154 && recovered.compareTo(sacr) == 0) 155 { 156 lg.println("Passed test " + size + "/" + deathpoint 157 + ": rolled back to v1"); 158 } else if (recovered.length() == (sacr.length() + f.length()) 159 && recovered.compareTo(sacr + f) == 0) 160 { 161 lg.println("Passed test " + size + "/" + deathpoint 162 + ": committed to v2"); 163 } else { 164 final String q = "\""; 165 lg.println("Wrote " + sacr.length() + ": " + q + sacr + q); 166 lg.println("Simulated failure during write " 167 + f.length() + ": " + q + f + q); 168 lg.println("Recovered " + recovered.length() + ": " + q + recovered + q); 169 throw new InternalError("Failed test " + size + "/" + deathpoint 170 + " (size/deathpoint):"); 171 } 172 } 173 } 174 } catch (Exception e) { 175 e.printStackTrace(lg); 176 //return (Status.failed 177 throw (new RuntimeException 178 ("Exception in sanity test for sun.rmi.log.ReliableLog")); 179 } 180 //return (Status.passed ("OKAY")); 181 } 182 183 private String contents; 184 transient private StringBuffer trc = null; 185 186 public Recovery() 187 { 188 super(); 189 if (this.contents == null) 190 this.contents = "?"; 191 } 192 193 // implements LogHandler.initialSnapshot() 194 public Object initialSnapshot() 195 throws Exception 196 { 197 this.contents = ""; 198 return (this); 199 } 200 201 // implements LogHandler.applyUpdate() 202 public Object applyUpdate (Object update, Object state) 203 throws Exception 204 { 205 // basicUpdate appends the string 206 ((Recovery)state).basicUpdate ((String)update); 207 return (state); 208 } 209 210 // an "update" is a short string to append to this.contents (must ignore state) 211 public void basicUpdate (String extra) 212 { 213 this.contents = this.contents + extra; 214 } 215} 216