blob: a1c05e3b74697454a39ad29e5c8137e471065471 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
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}