J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1998-2002 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 21 | * have any 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 | |
| 43 | import java.io.File; |
| 44 | import java.io.IOException; |
| 45 | import java.io.PrintStream; |
| 46 | import java.io.Serializable; |
| 47 | import sun.rmi.log.LogHandler; |
| 48 | import sun.rmi.log.ReliableLog; |
| 49 | |
| 50 | //import javasoft.sqe.harness.Status; |
| 51 | //import javasoft.sqe.harness.Test; |
| 52 | |
| 53 | public 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 | } |