File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\store\RecoverTester.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.store;
8
9 import java.io.OutputStreamWriter;
10 import java.io.PrintWriter;
11 import java.sql.SQLException;
12 import java.util.HashSet;
13 import java.util.Properties;
14 import org.h2.constant.ErrorCode;
15 import org.h2.engine.ConnectionInfo;
16 import org.h2.engine.Constants;
17 import org.h2.engine.Database;
18 import org.h2.engine.Session;
19 import org.h2.message.DbException;
20 import org.h2.store.fs.FilePathRec;
21 import org.h2.store.fs.FileUtils;
22 import org.h2.store.fs.Recorder;
23 import org.h2.tools.Recover;
24 import org.h2.util.IOUtils;
25 import org.h2.util.New;
26 import org.h2.util.StringUtils;
27 import org.h2.util.Utils;
28
29 /**
30 * A tool that simulates a crash while writing to the database, and then
31 * verifies the database doesn't get corrupt.
32 */
33 public class RecoverTester implements Recorder {
34
35 private static RecoverTester instance;
36
37 private String testDatabase = "memFS:reopen";
38 private int writeCount = Utils.getProperty("h2.recoverTestOffset", 0);
39 private int testEvery = Utils.getProperty("h2.recoverTest", 64);
40 private final long maxFileSize = Utils.getProperty("h2.recoverTestMaxFileSize", Integer.MAX_VALUE) * 1024L * 1024;
41 private int verifyCount;
42 private final HashSet<String> knownErrors = New.hashSet();
43 private volatile boolean testing;
44
45 /**
46 * Initialize the recover test.
47 *
48 * @param recoverTest the value of the recover test parameter
49 */
50 public static synchronized void init(String recoverTest) {
51 RecoverTester tester = RecoverTester.getInstance();
52 if (StringUtils.isNumber(recoverTest)) {
53 tester.setTestEvery(Integer.parseInt(recoverTest));
54 }
55 FilePathRec.setRecorder(tester);
56 }
57
58 public static synchronized RecoverTester getInstance() {
59 if (instance == null) {
60 instance = new RecoverTester();
61 }
62 return instance;
63 }
64
65 public void log(int op, String fileName, byte[] data, long x) {
66 if (op != Recorder.WRITE && op != Recorder.TRUNCATE) {
67 return;
68 }
69 if (!fileName.endsWith(Constants.SUFFIX_PAGE_FILE)) {
70 return;
71 }
72 writeCount++;
73 if ((writeCount % testEvery) != 0) {
74 return;
75 }
76 if (FileUtils.size(fileName) > maxFileSize) {
77 // System.out.println(fileName + " " + IOUtils.length(fileName));
78 return;
79 }
80 if (testing) {
81 // avoid deadlocks
82 return;
83 }
84 testing = true;
85 PrintWriter out = null;
86 try {
87 out = new PrintWriter(
88 new OutputStreamWriter(
89 FileUtils.newOutputStream(fileName + ".log", true)));
90 testDatabase(fileName, out);
91 } finally {
92 IOUtils.closeSilently(out);
93 testing = false;
94 }
95 }
96
97 private synchronized void testDatabase(String fileName, PrintWriter out) {
98 out.println("+ write #" + writeCount + " verify #" + verifyCount);
99 try {
100 FileUtils.copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
101 verifyCount++;
102 // avoid using the Engine class to avoid deadlocks
103 Properties p = new Properties();
104 p.setProperty("user", "");
105 p.setProperty("password", "");
106 ConnectionInfo ci = new ConnectionInfo("jdbc:h2:" + testDatabase + ";FILE_LOCK=NO;TRACE_LEVEL_FILE=0", p);
107 Database database = new Database(ci, null);
108 // close the database
109 Session session = database.getSystemSession();
110 session.prepare("script to '" + testDatabase + ".sql'").query(0);
111 session.prepare("shutdown immediately").update();
112 database.removeSession(null);
113 // everything OK - return
114 return;
115 } catch (DbException e) {
116 SQLException e2 = DbException.toSQLException(e);
117 int errorCode = e2.getErrorCode();
118 if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
119 return;
120 } else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
121 return;
122 }
123 e.printStackTrace(System.out);
124 } catch (Exception e) {
125 // failed
126 int errorCode = 0;
127 if (e instanceof SQLException) {
128 errorCode = ((SQLException) e).getErrorCode();
129 }
130 if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
131 return;
132 } else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
133 return;
134 }
135 e.printStackTrace(System.out);
136 }
137 out.println("begin ------------------------------ " + writeCount);
138 try {
139 Recover.execute(fileName.substring(0, fileName.lastIndexOf('/')), null);
140 } catch (SQLException e) {
141 // ignore
142 }
143 testDatabase += "X";
144 try {
145 FileUtils.copy(fileName, testDatabase + Constants.SUFFIX_PAGE_FILE);
146 // avoid using the Engine class to avoid deadlocks
147 Properties p = new Properties();
148 ConnectionInfo ci = new ConnectionInfo("jdbc:h2:" + testDatabase + ";FILE_LOCK=NO", p);
149 Database database = new Database(ci, null);
150 // close the database
151 database.removeSession(null);
152 } catch (Exception e) {
153 int errorCode = 0;
154 if (e instanceof DbException) {
155 e = ((DbException) e).getSQLException();
156 errorCode = ((SQLException) e).getErrorCode();
157 }
158 if (errorCode == ErrorCode.WRONG_USER_OR_PASSWORD) {
159 return;
160 } else if (errorCode == ErrorCode.FILE_ENCRYPTION_ERROR_1) {
161 return;
162 }
163 StringBuilder buff = new StringBuilder();
164 StackTraceElement[] list = e.getStackTrace();
165 for (int i = 0; i < 10 && i < list.length; i++) {
166 buff.append(list[i].toString()).append('\n');
167 }
168 String s = buff.toString();
169 if (!knownErrors.contains(s)) {
170 out.println(writeCount + " code: " + errorCode + " " + e.toString());
171 e.printStackTrace(System.out);
172 knownErrors.add(s);
173 } else {
174 out.println(writeCount + " code: " + errorCode);
175 }
176 }
177 }
178
179 public void setTestEvery(int testEvery) {
180 this.testEvery = testEvery;
181 }
182
183 }