You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by su...@apache.org on 2006/07/26 19:11:34 UTC
svn commit: r425781 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/store/raw/
testing/org/apache/derbyTesting/functionTests/master/
testing/org/apache/derbyTesting/functionTests/suites/
testing/org/apache/derbyTesting/functionTests/tests/...
Author: suresht
Date: Wed Jul 26 10:11:33 2006
New Revision: 425781
URL: http://svn.apache.org/viewvc?rev=425781&view=rev
Log:
DERBY -1156 (partial) re-encryption of the database.
This patch adds a new test that tests recovery of the database
if the engine crashes just before committing the re-encryption
with a new password phrase. Crash is simulated using the debug flags.
Added:
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out (with props)
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java (with props)
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java?rev=425781&r1=425780&r2=425781&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/raw/RawStore.java Wed Jul 26 10:11:33 2006
@@ -1323,6 +1323,19 @@
}
+ /**
+ * Re-encryption testing debug flags, that are used to
+ * simulate error/crash conditions for testing purposes.
+ */
+
+ /*
+ * Set to true to make the re-encryption fail just
+ * before it is committed.
+ */
+
+ public static final String TEST_REENCRYPT_CRASH_BEFORE_COMMT =
+ SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_BEFORE_COMMT" : null ;
+
/*
* Configure the database for encryption, with the specified
@@ -1379,6 +1392,20 @@
transaction.abort();
}
else {
+
+ if (SanityManager.DEBUG)
+ {
+ // if the test debug flag is set, stop the
+ // re-encryption of the database here and
+ // throw an expception.
+ if (SanityManager.DEBUG_ON(TEST_REENCRYPT_CRASH_BEFORE_COMMT))
+ {
+ throw StandardException.newException(
+ SQLState.LOG_IO_ERROR,
+ new IOException(TEST_REENCRYPT_CRASH_BEFORE_COMMT));
+ }
+ }
+
transaction.commit();
// TODO : handle the case where if engine crashes
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out?rev=425781&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out Wed Jul 26 10:11:33 2006
@@ -0,0 +1,2 @@
+Begin ReEncryptCrashRecovery Test
+End ReEncryptCrashRecovery Test
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/ReEncryptCrashRecovery.out
------------------------------------------------------------------------------
svn:eol-style = native
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall?rev=425781&r1=425780&r2=425781&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/suites/encryptionAll.runall Wed Jul 26 10:11:33 2006
@@ -4,3 +4,4 @@
store/encryptDatabaseTest1.sql
store/encryptDatabaseTest2.sql
store/encryptionKey_jar.sql
+store/ReEncryptCrashRecovery.java
Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java?rev=425781&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java Wed Jul 26 10:11:33 2006
@@ -0,0 +1,403 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.store.ReEncryptCrashRecovery
+
+ Copyright 2006 The Apache Software Foundation or its licensors, as applicable.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.tests.store;
+import java.sql.Connection;
+import java.sql.Statement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import org.apache.derby.tools.ij;
+import org.apache.derbyTesting.functionTests.util.TestUtil;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
+/*
+ * This class tests crash/recovery scenarions during re-encryption of
+ * databas. Debug flags are used to simulate crashes during the
+ * re-encrytpion.
+ *
+ * Unlike the other recovery tests which do a setup and recovery as different
+ * tests, Incase of re-encryption crash/recovery can be simulated in one
+ * test itself because re-encryption is done at boot time. When debug flags are
+ * set database boot itself fails. To test the recovery, it is just a matter
+ * of clearing up the debug flag and rebooting the database.
+ *
+ * In Non debug mode, this tests just acts as a plain re-encryption test,
+ * just testing re-encrytpion multiple times.
+ *
+ * @author <a href="mailto:suresh.thalamati@gmail.com">Suresh Thalamati</a>
+ * @version 1.0
+ */
+
+public class ReEncryptCrashRecovery
+{
+
+ private static final String TEST_DATABASE_NAME = "wombat_pwd" ;
+ private static final String TEST_TABLE_NAME = "emp";
+ private static final String OLD_PASSWORD = "xyz1234abc";
+ private static final String NEW_PASSWORD = "new1234xyz";
+
+ ReEncryptCrashRecovery() {
+
+ }
+
+
+ /*
+ * Test Re-encrytpion crash/recovery scenarios.
+ */
+ private void runTest() throws Exception {
+ logMessage("Begin ReEncryptCrashRecovery Test");
+ createEncryptedDatabase();
+ Connection conn = TestUtil.getConnection(TEST_DATABASE_NAME,
+ null);
+ createTable(conn, TEST_TABLE_NAME);
+ //load some rows
+ insert(conn, TEST_TABLE_NAME, 100);
+ conn.commit();
+ //shutdown the test db
+ shutdown(TEST_DATABASE_NAME);
+
+ // re-enryption crash/recovery test cases.
+ crashBeforeCommit();
+ recover_crashBeforeCommit();
+ //shutdown the test db
+ shutdown(TEST_DATABASE_NAME);
+
+ logMessage("End ReEncryptCrashRecovery Test");
+ }
+
+
+ /** *************************************************
+ * Crash/recovery test scenarios during re-encryption.
+ ****************************************************/
+
+ /*
+ * Attempt to re-encrypt the database and force it to fail
+ * using debug flags just before the commit.
+ */
+ private void crashBeforeCommit() {
+ // Re-encrytption crash before commit
+ setDebugFlag(TEST_REENCRYPT_CRASH_BEFORE_COMMT);
+
+ SQLException sqle = null;
+ try {
+ reEncryptDatabase(OLD_PASSWORD, NEW_PASSWORD);
+ }catch (SQLException se) {
+ // re-encryption of the database should have failed,
+ // at the specified debug flag.
+ sqle = se;
+ }
+
+ // check that database boot failed at the set debug flag.
+ verifyException(sqle, TEST_REENCRYPT_CRASH_BEFORE_COMMT);
+ // clear the debug flag.
+ clearDebugFlag(TEST_REENCRYPT_CRASH_BEFORE_COMMT);
+ }
+
+
+ /*
+ * Recover the database that failied during re-encryption and
+ * perform some simple sanity check on the database.
+ */
+ private void recover_crashBeforeCommit() throws SQLException{
+ // starting recovery of database with failed Re-encrytpion
+ // in debug mode;
+ Connection conn = bootDatabase(OLD_PASSWORD);
+ // verify the contents of the db are ok.
+ runConsistencyChecker(conn, TEST_TABLE_NAME);
+ // insert some rows, this might fail if anyhing is
+ // wrong in the logging system setup.
+ insert(conn, TEST_TABLE_NAME, 100);
+ conn.close();
+ }
+
+
+
+ // Debug flags that needs to be set to simulate a crash
+ // at different points during re-encryption of the database.
+ // these flags should match the flags in the engine code;
+ // these are redifined here to avoid pulling the engine code
+ // into the tests.
+
+
+ /*
+ Set to true if we want the re-encryption to crash just
+ before the commit.
+ */
+
+ public static final String TEST_REENCRYPT_CRASH_BEFORE_COMMT =
+ SanityManager.DEBUG ? "TEST_REENCRYPT_CRASH_BEFORE_COMMT" : null ;
+
+
+
+ void setDebugFlag(String debugFlag) {
+ if (SanityManager.DEBUG) {
+ SanityManager.DEBUG_SET(debugFlag);
+ }
+ }
+
+ void clearDebugFlag(String debugFlag) {
+ if (SanityManager.DEBUG) {
+ SanityManager.DEBUG_CLEAR(debugFlag);
+ }
+ }
+
+ /*
+ * verify that database boot failed when a debug flag is set.
+ */
+ private void verifyException(SQLException sqle, String debugFlag)
+ {
+ if (sqle != null)
+ {
+ if (sqle.getSQLState() != null &&
+ sqle.getSQLState().equals("XJ040"))
+ {
+ // boot failed as expected with the debug flag
+ }else
+ {
+ dumpSQLException(sqle);
+ }
+ } else {
+ if (SanityManager.DEBUG)
+ {
+ logMessage("Did not crash at " + debugFlag);
+ }
+ }
+ }
+
+
+ /*
+ * create the tables that are used by this test.
+ * @param conn connection to the database.
+ * @param tableName Name of the table to create.
+ * @exception SQLException if any database exception occurs.
+ */
+ void createTable(Connection conn,
+ String tableName) throws SQLException {
+
+ Statement s = conn.createStatement();
+ s.executeUpdate("CREATE TABLE " + tableName +
+ "(id INT," +
+ "name CHAR(200))");
+ s.executeUpdate("create index " + tableName + "_id_idx on " +
+ tableName + "(id)");
+ s.close();
+ }
+
+
+ /**
+ * Run some consistency checks.
+ * @param conn connection to the database.
+ * @param tableName consistency checks are performed on this table.
+ * @exception SQLException if any database exception occurs.
+ */
+ void runConsistencyChecker(Connection conn,
+ String tableName) throws SQLException {
+ Statement stmt = conn.createStatement();
+ stmt.execute("values SYSCS_UTIL.SYSCS_CHECK_TABLE('APP', 'EMP')");
+ // check the data in the EMP table.
+ select(conn, tableName);
+ }
+
+
+ /**
+ * Insert some rows into the specified table.
+ * @param conn connection to the database.
+ * @param tableName name of the table that rows are inserted.
+ * @param rowCount Number of rows to Insert.
+ * @exception SQLException if any database exception occurs.
+ */
+ void insert(Connection conn,
+ String tableName,
+ int rowCount) throws SQLException
+ {
+
+ PreparedStatement ps = conn.prepareStatement("INSERT INTO " +
+ tableName +
+ " VALUES(?,?)");
+ int startId = findMax(conn, tableName);
+ for (int i = startId; i < rowCount; i++) {
+
+ ps.setInt(1, i); // ID
+ ps.setString(2 , "skywalker" + i);
+ ps.executeUpdate();
+ }
+ conn.commit();
+ ps.close();
+ }
+
+ /**
+ * find a max value on the give table.
+ * @param conn connection to the database.
+ * @param tableName name of the table.
+ * @exception SQLException if any database exception occurs.
+ */
+ private int findMax(Connection conn,
+ String tableName) throws SQLException
+ {
+ Statement s = conn.createStatement();
+ ResultSet rs = s.executeQuery("SELECT max(ID) from " +
+ tableName);
+ rs.next();
+ return rs.getInt(1);
+ }
+
+
+ /*
+ * read the rows in the table.
+ * @param conn connection to the database.
+ * @param tableName select operation is perfomed on this table.
+ * @exception SQLException if any database exception occurs.
+ */
+ void select(Connection conn ,
+ String tableName) throws SQLException
+ {
+
+ Statement s = conn.createStatement();
+ ResultSet rs = s.executeQuery("SELECT ID, name from " +
+ tableName + " order by id" );
+ int count = 0;
+ int id = 0;
+ while(rs.next())
+ {
+ int tid = rs.getInt(1);
+ String name = rs.getString(2);
+ if(name.equals("skywalker" + id) && tid!= id)
+ {
+ logMessage("DATA IN THE TABLE IS NOT AS EXPECTED");
+ logMessage("Got :ID=" + tid + " Name=:" + name);
+ logMessage("Expected: ID=" + id + "Name=" + "skywalker" + id );
+ }
+
+ id++;
+ count++;
+ }
+
+ rs.close();
+ s.close();
+ conn.commit();
+ }
+
+
+
+ /*
+ * create an encrypted database.
+ */
+ private void createEncryptedDatabase() throws SQLException
+ {
+ TestUtil.getConnection(TEST_DATABASE_NAME,
+ "create=true;dataEncryption=true;bootPassword=" +
+ OLD_PASSWORD);
+ }
+
+ /**
+ * Re-encrypt the database.
+ * @param currentPassword current boot password.
+ * @param newPassword new password to boot the database
+ * after successful re-encryption.
+ * @exception SQLException if any database exception occurs.
+ */
+ private void reEncryptDatabase(String currentPassword,
+ String newPassword)
+ throws SQLException
+ {
+ // re-encrypt the database.
+ String connAttrs = "bootPassword=" + currentPassword +
+ ";newBootPassword=" + newPassword;
+ TestUtil.getConnection(TEST_DATABASE_NAME, connAttrs);
+ }
+
+
+ /**
+ * Encrypt an un-encrypted atabase.
+ * @param password boot password of the database.
+ * @exception SQLException if any database exception occurs.
+ */
+ private void encryptDatabase(String password)
+ throws SQLException
+ {
+ //encrypt an existing database.
+ String connAttrs = "dataEncryption=true;bootPassword=" +
+ password ;
+
+ TestUtil.getConnection(TEST_DATABASE_NAME, connAttrs);
+ }
+
+
+ /**
+ * Boot the database.
+ * @param password boot password of the database.
+ * @exception SQLException if any database exception occurs.
+ */
+ Connection bootDatabase(String password) throws SQLException {
+
+ return TestUtil.getConnection(TEST_DATABASE_NAME,
+ "bootPassword=" + password);
+ }
+
+
+
+ /**
+ * Shutdown the datbase
+ * @param dbName Name of the database to shutdown.
+ */
+ void shutdown(String dbName) {
+
+ try{
+ //shutdown
+ TestUtil.getConnection(dbName, "shutdown=true");
+ }catch(SQLException se){
+ if (se.getSQLState() == null || !(se.getSQLState().equals("08006")))
+ {
+ // database was not shutdown properly
+ dumpSQLException(se);
+ }
+ }
+ }
+
+ /**
+ * dump the SQLException to the standard output.
+ */
+ private void dumpSQLException(SQLException sqle) {
+
+ org.apache.derby.tools.JDBCDisplayUtil. ShowSQLException(System.out, sqle);
+ sqle.printStackTrace(System.out);
+ }
+
+
+ void logMessage(String str)
+ {
+ System.out.println(str);
+ }
+
+
+ public static void main(String[] argv) throws Throwable {
+
+ ReEncryptCrashRecovery test = new ReEncryptCrashRecovery();
+ try {
+ test.runTest();
+ }
+ catch (SQLException sqle) {
+ org.apache.derby.tools.JDBCDisplayUtil.ShowSQLException(
+ System.out, sqle);
+ sqle.printStackTrace(System.out);
+ }
+ }
+}
Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/ReEncryptCrashRecovery.java
------------------------------------------------------------------------------
svn:eol-style = native