1 5 package org.h2.test.db; 6 7 import java.sql.Connection ; 8 import java.sql.DatabaseMetaData ; 9 import java.sql.ResultSet ; 10 import java.sql.SQLException ; 11 import java.sql.Statement ; 12 import java.util.ArrayList ; 13 import java.util.Random ; 14 15 import org.h2.engine.Constants; 16 import org.h2.engine.Database; 17 import org.h2.jdbc.JdbcConnection; 18 import org.h2.test.TestBase; 19 import org.h2.tools.FileBase; 20 import org.h2.util.FileUtils; 21 import org.h2.util.JdbcUtils; 22 23 public class TestPowerOff extends TestBase { 24 25 private String dbName = "powerOff"; 26 private String dir, url; 27 28 private int maxPowerOffCount; 29 30 public void test() throws Exception { 31 if(config.memory || config.logMode==0) { 32 return; 33 } 34 if(config.big) { 35 dir = BASE_DIR; 36 } else { 37 dir = "inmemory:"; 38 } 39 url = dir + "/" + dbName + ";file_lock=no"; 40 testSummaryCrash(); 41 testCrash(); 42 testShutdown(); 43 testNoIndexFile(); 44 testMemoryTables(); 45 testPersistentTables(); 46 } 47 48 private void testSummaryCrash() throws Exception { 49 if(config.networked) { 50 return; 51 } 52 deleteDb(dir, dbName); 53 Connection conn = getConnection(url); 54 Statement stat = conn.createStatement(); 55 for(int i=0; i<10; i++) { 56 stat.execute("CREATE TABLE TEST" + i + "(ID INT PRIMARY KEY, NAME VARCHAR)"); 57 for(int j=0; j<10; j++) { 58 stat.execute("INSERT INTO TEST" + i + " VALUES("+j+", 'Hello')"); 59 } 60 } 61 for(int i=0; i<10; i+=2) { 62 stat.execute("DROP TABLE TEST" + i); 63 } 64 stat.execute("SET WRITE_DELAY 0"); 65 stat.execute("CHECKPOINT"); 66 for(int j=0; j<10; j++) { 67 stat.execute("INSERT INTO TEST1 VALUES("+(10+j)+", 'World')"); 68 } 69 stat.execute("SHUTDOWN IMMEDIATELY"); 70 JdbcUtils.closeSilently(conn); 71 conn = getConnection(url); 72 stat = conn.createStatement(); 73 for(int i=1; i<10; i+=2) { 74 ResultSet rs = stat.executeQuery("SELECT * FROM TEST" + i + " ORDER BY ID"); 75 for(int j=0; j<10; j++) { 76 rs.next(); 77 check(rs.getInt(1), j); 78 check(rs.getString(2), "Hello"); 79 } 80 if(i == 1) { 81 for(int j=0; j<10; j++) { 82 rs.next(); 83 check(rs.getInt(1), j + 10); 84 check(rs.getString(2), "World"); 85 } 86 } 87 checkFalse(rs.next()); 88 } 89 conn.close(); 90 } 91 92 private void testCrash() throws Exception { 93 if(config.networked) { 94 return; 95 } 96 deleteDb(dir, dbName); 97 Random random = new Random (1); 98 Constants.RUN_FINALIZERS = false; 99 int repeat = getSize(1, 20); 100 for(int i=0; i<repeat; i++) { 101 Connection conn = getConnection(url); 102 conn.close(); 103 conn = getConnection(url); 104 Statement stat = conn.createStatement(); 105 stat.execute("SET WRITE_DELAY 0"); 106 ((JdbcConnection)conn).setPowerOffCount(random.nextInt(100)); 107 try { 108 stat.execute("DROP TABLE IF EXISTS TEST"); 109 stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 110 conn.setAutoCommit(false); 111 int len = getSize(3, 100); 112 for (int j=0; j<len; j++) { 113 stat.execute("INSERT INTO TEST VALUES("+j+", 'Hello')"); 114 if(random.nextInt(5) == 0) { 115 conn.commit(); 116 } 117 if(random.nextInt(10) == 0) { 118 stat.execute("DROP TABLE IF EXISTS TEST"); 119 stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 120 } 121 } 122 stat.execute("DROP TABLE IF EXISTS TEST"); 123 conn.close(); 124 } catch(SQLException e) { 125 if(!e.getSQLState().equals("90098")) { 126 TestBase.logError("power", e); 127 } 128 } 129 } 130 } 131 132 private void testShutdown() throws Exception { 133 deleteDb(dir, dbName); 134 Connection conn = getConnection(url); 135 Statement stat = conn.createStatement(); 136 stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 137 stat.execute("INSERT INTO TEST VALUES(1, 'Hello')"); 138 stat.execute("SHUTDOWN"); 139 conn.close(); 140 141 conn = getConnection(url); 142 stat = conn.createStatement(); 143 ResultSet rs = stat.executeQuery("SELECT * FROM TEST"); 144 check(rs.next()); 145 checkFalse(rs.next()); 146 conn.close(); 147 } 148 149 private void testNoIndexFile() throws Exception { 150 if(config.networked) { 151 return; 152 } 153 deleteDb(dir, dbName); 154 Connection conn = getConnection(url); 155 Statement stat = conn.createStatement(); 156 stat.execute("CREATE MEMORY TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 157 stat.execute("INSERT INTO TEST VALUES(1, 'Hello')"); 158 ((JdbcConnection)conn).setPowerOffCount(1); 159 try { 160 stat.execute("INSERT INTO TEST VALUES(2, 'Hello')"); 161 stat.execute("CHECKPOINT"); 162 error("should not work!"); 163 } catch(SQLException e) { 164 } 166 boolean deleted = false; 167 ArrayList files = FileBase.getDatabaseFiles(dir, dbName, false); 168 for(int i=0; i<files.size(); i++) { 169 String fileName = (String ) files.get(i); 170 if(fileName.endsWith(Constants.SUFFIX_INDEX_FILE)) { 171 FileUtils.delete(fileName); 172 deleted = true; 173 } 174 } 175 check(deleted); 176 conn = getConnection(url); 177 conn.close(); 178 } 179 180 private void testMemoryTables() throws Exception { 181 if(config.networked) { 182 return; 183 } 184 deleteDb(dir, dbName); 185 186 Connection conn = getConnection(url); 187 Statement stat = conn.createStatement(); 188 stat.execute("CREATE MEMORY TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 189 stat.execute("INSERT INTO TEST VALUES(1, 'Hello')"); 190 stat.execute("CHECKPOINT"); 191 ((JdbcConnection)conn).setPowerOffCount(1); 192 try { 193 stat.execute("INSERT INTO TEST VALUES(2, 'Hello')"); 194 stat.execute("INSERT INTO TEST VALUES(3, 'Hello')"); 195 stat.execute("CHECKPOINT"); 196 error("should have failed!"); 197 } catch(Exception e) { 198 } 200 201 ((JdbcConnection)conn).setPowerOffCount(0); 202 conn = getConnection(url); 203 stat = conn.createStatement(); 204 ResultSet rs = stat.executeQuery("SELECT COUNT(*) FROM TEST"); 205 rs.next(); 206 check(rs.getInt(1), 1); 207 conn.close(); 208 } 209 210 private void testPersistentTables() throws Exception { 211 if(config.networked) { 212 return; 213 } 214 deleteDb(dir, dbName); 215 216 testRun(true); 218 int max = maxPowerOffCount; 219 trace("max="+max); 220 runTest(0, max, true); 221 recoverAndCheckConsistency(); 222 runTest(0, max, false); 223 recoverAndCheckConsistency(); 224 } 225 226 void runTest(int min, int max, boolean withConsistencyCheck) throws Exception { 227 for(int i=min; i<max; i++) { 228 deleteDb(dir, dbName); 229 Database.setInitialPowerOffCount(i); 230 int expect = testRun(false); 231 if(withConsistencyCheck) { 232 int got = recoverAndCheckConsistency(); 233 trace("test "+i+" of "+max+" expect="+expect+" got="+got); 234 } else { 235 trace("test "+i+" of "+max+" expect="+expect); 236 } 237 } 238 Database.setInitialPowerOffCount(0); 239 } 240 241 int testRun(boolean init) throws Exception { 242 if(init) { 243 Database.setInitialPowerOffCount(Integer.MAX_VALUE); 244 } 245 int state = 0; 246 try { 247 Connection conn = getConnection(url); 248 Statement stat = conn.createStatement(); 249 stat.execute("SET WRITE_DELAY 0"); 250 stat.execute("CREATE TABLE IF NOT EXISTS TEST(ID INT PRIMARY KEY, NAME VARCHAR(255))"); 251 state = 1; 252 conn.setAutoCommit(false); 253 stat.execute("INSERT INTO TEST VALUES(1, 'Hello')"); 254 stat.execute("INSERT INTO TEST VALUES(2, 'World')"); 255 conn.commit(); 256 state = 2; 257 stat.execute("UPDATE TEST SET NAME='Hallo' WHERE ID=1"); 258 stat.execute("UPDATE TEST SET NAME='Welt' WHERE ID=2"); 259 conn.commit(); 260 state = 3; 261 stat.execute("DELETE FROM TEST WHERE ID=1"); 262 stat.execute("DELETE FROM TEST WHERE ID=2"); 263 conn.commit(); 264 state = 1; 265 stat.execute("DROP TABLE TEST"); 266 state = 0; 267 if(init) { 268 maxPowerOffCount = Integer.MAX_VALUE - ((JdbcConnection)conn).getPowerOffCount(); 269 } 270 conn.close(); 271 } catch(SQLException e) { 272 if(e.getSQLState().equals("90098")) { 273 } else { 275 throw e; 276 } 277 } 278 return state; 279 } 280 281 int recoverAndCheckConsistency() throws Exception { 282 int state; 283 Database.setInitialPowerOffCount(0); 284 Connection conn = getConnection(url); 285 if(((JdbcConnection)conn).getPowerOffCount() != 0) { 286 error("power off count is not 0"); 287 } 288 Statement stat = conn.createStatement(); 289 DatabaseMetaData meta = conn.getMetaData(); 290 ResultSet rs = meta.getTables(null, null, "TEST", null); 291 if(!rs.next()) { 292 state = 0; 293 } else { 294 rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID"); 296 if(!rs.next()) { 297 state = 1; 298 } else { 299 check(rs.getInt(1), 1); 300 String name1 = rs.getString(2); 301 check(rs.next()); 302 check(rs.getInt(1), 2); 303 String name2 = rs.getString(2); 304 checkFalse(rs.next()); 305 if("Hello".equals(name1)) { 306 check(name2, "World"); 307 state = 2; 308 } else { 309 check(name1, "Hallo"); 310 check(name2, "Welt"); 311 state = 3; 312 } 313 } 314 } 315 conn.close(); 316 return state; 317 } 318 319 } 320 | Popular Tags |