Package com.sleepycat.je.log

Source Code of com.sleepycat.je.log.IOExceptionTest

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002-2005
*      Sleepycat Software.  All rights reserved.
*
* $Id: IOExceptionTest.java,v 1.4 2005/06/09 20:35:17 cwl Exp $
*/

package com.sleepycat.je.log;

import java.io.File;
import java.io.IOException;

import junit.framework.TestCase;

import com.sleepycat.je.CheckpointConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.EnvironmentStats;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.config.EnvironmentParams;
import com.sleepycat.je.util.TestUtils;

public class IOExceptionTest extends TestCase {

    static private final boolean DEBUG = false;

    private Environment env;
    private Database db;
    private File envHome;

    public IOExceptionTest()
        throws Exception {

        envHome = new File(System.getProperty(TestUtils.DEST_DIR));
    }

    public void setUp()
        throws IOException, DatabaseException {

        TestUtils.removeFiles("Setup", envHome, FileManager.JE_SUFFIX);
    }
   
    public void tearDown()
        throws IOException, DatabaseException {

  FileManager.IO_EXCEPTION_TESTING = false;
  db.close();
        env.close();
        TestUtils.removeFiles("TearDown", envHome, FileManager.JE_SUFFIX);
    }

    public void testIOExceptionNoRecovery()
  throws Throwable {

  doIOExceptionTest(false);
    }

    public void testIOExceptionWithRecovery()
  throws Throwable {

  doIOExceptionTest(true);
    }

    public void testEviction()
  throws Exception {

  try {
      createDatabase(200000);
 
      final int N_RECS = 25;

      CheckpointConfig chkConf = new CheckpointConfig();
      chkConf.setForce(true);
      Transaction txn = env.beginTransaction(null, null);
      int keyInt = 0;
      FileManager.IO_EXCEPTION_TESTING = true;
      for (int i = 0; i < N_RECS; i++) {
    String keyStr = Integer.toString(keyInt);
    DatabaseEntry key =
        new DatabaseEntry(keyStr.getBytes());
    DatabaseEntry data =
        new DatabaseEntry(("d" + keyStr).getBytes());
    try {
        assertTrue(db.put(txn, key, data) ==
             OperationStatus.SUCCESS);
    } catch (DatabaseException DE) {
        fail("unexpected DatabaseException");
        break;
    }
      }

      try {
    env.checkpoint(chkConf);
    fail("expected DatabaseException");
      } catch (DatabaseException DE) {
      }

      EnvironmentStats stats = env.getStats(null);
      assertTrue((stats.getNFullINFlush() +
      stats.getNFullBINFlush()) > 0);

      /* Read back the data and make sure it all looks ok. */
      for (int i = 0; i < N_RECS; i++) {
    String keyStr = Integer.toString(keyInt);
    DatabaseEntry key =
        new DatabaseEntry(keyStr.getBytes());
    DatabaseEntry data = new DatabaseEntry();
    try {
        assertTrue(db.get(txn, key, data, null) ==
             OperationStatus.SUCCESS);
        assertEquals(new String(data.getData()), "d" + keyStr);
    } catch (DatabaseException DE) {
        fail("unexpected DatabaseException");
        break;
    }
      }

      /*
       * Now we have some IN's in the log buffer and there have been
       * IOExceptions that will later force rewriting that buffer.
       */
      FileManager.IO_EXCEPTION_TESTING = false;
      try {
    txn.commit();
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }
  } catch (Exception E) {
      E.printStackTrace();
  }
    }

    public void testLogBufferOverflowAbortNoDupes()
  throws Exception {

  doLogBufferOverflowTest(false, false);
    }

    public void testLogBufferOverflowCommitNoDupes()
  throws Exception {

  doLogBufferOverflowTest(true, false);
    }

    public void testLogBufferOverflowAbortDupes()
  throws Exception {

  doLogBufferOverflowTest(false, true);
    }

    public void testLogBufferOverflowCommitDupes()
  throws Exception {

  doLogBufferOverflowTest(true, true);
    }

    private void doLogBufferOverflowTest(boolean abort, boolean dupes)
  throws Exception {

  try {
      EnvironmentConfig envConfig = TestUtils.initEnvConfig();
      envConfig.setTransactional(true);
      envConfig.setAllowCreate(true);
      envConfig.setCacheSize(100000);
      envConfig.setConfigParam("java.util.logging.level", "OFF");
      env = new Environment(envHome, envConfig);

      String databaseName = "ioexceptiondb";
      DatabaseConfig dbConfig = new DatabaseConfig();
      dbConfig.setAllowCreate(true);
      dbConfig.setSortedDuplicates(true);
      dbConfig.setTransactional(true);
      db = env.openDatabase(null, databaseName, dbConfig);
 
      Transaction txn = env.beginTransaction(null, null);
      DatabaseEntry oneKey =
    (dupes ?
     new DatabaseEntry("2".getBytes()) :
     new DatabaseEntry("1".getBytes()));
      DatabaseEntry oneData =
    new DatabaseEntry(new byte[10]);
      DatabaseEntry twoKey =
    new DatabaseEntry("2".getBytes());
      DatabaseEntry twoData =
    new DatabaseEntry(new byte[100000]);
      if (dupes) {
    DatabaseEntry temp = oneKey;
    oneKey = oneData;
    oneData = temp;
    temp = twoKey;
    twoKey = twoData;
    twoData = temp;
      }

      try {
    assertTrue(db.put(txn, oneKey, oneData) ==
         OperationStatus.SUCCESS);
    db.put(txn, twoKey, twoData);
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

      /* Read back the data and make sure it all looks ok. */
      try {
    assertTrue(db.get(txn, oneKey, oneData, null) ==
         OperationStatus.SUCCESS);
    assertTrue(oneData.getData().length == (dupes ? 1 : 10));
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

      try {
    assertTrue(db.get(txn, twoKey, twoData, null) ==
         OperationStatus.SUCCESS);
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

      try {
    if (abort) {
        txn.abort();
    } else {
        txn.commit();
    }
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

      /* Read back the data and make sure it all looks ok. */
      try {
    assertTrue(db.get(null, oneKey, oneData, null) ==
         (abort ?
          OperationStatus.NOTFOUND :
          OperationStatus.SUCCESS));
    assertTrue(oneData.getData().length == (dupes ? 1 : 10));
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

      try {
    assertTrue(db.get(null, twoKey, twoData, null) ==
         (abort ?
          OperationStatus.NOTFOUND :
          OperationStatus.SUCCESS));
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }

  } catch (Exception E) {
      E.printStackTrace();
  }
    }

    public void testPutTransactionalWithIOException()
  throws Throwable {

  try {
      createDatabase(100000);

      Transaction txn = env.beginTransaction(null, null);
      int keyInt = 0;
      String keyStr;
      FileManager.IO_EXCEPTION_TESTING = true;

      /* Fill up the buffer until we see an IOException. */
      while (true) {
    keyStr = Integer.toString(++keyInt);
    DatabaseEntry key = new DatabaseEntry(keyStr.getBytes());
    DatabaseEntry data =
        new DatabaseEntry(("d" + keyStr).getBytes());
    try {
        assertTrue(db.put(txn, key, data) ==
             OperationStatus.SUCCESS);
    } catch (DatabaseException DE) {
        break;
    }
      }

      /* Buffer still hasn't been written.  This should also fail. */
      try {
    db.put(txn,
           new DatabaseEntry("shouldFail".getBytes()),
           new DatabaseEntry("shouldFailD".getBytes()));
    fail("expected DatabaseException");
      } catch (DatabaseException DE) {
    // expected
      }
      FileManager.IO_EXCEPTION_TESTING = false;

      /* Buffer should write out ok now. */
      try {
    db.put(txn,
           new DatabaseEntry("shouldNotFail".getBytes()),
           new DatabaseEntry("shouldNotFailD".getBytes()));
      } catch (DatabaseException DE) {
    fail("unexpected DatabaseException");
      }
      txn.commit();

      DatabaseEntry data = new DatabaseEntry();
      assertTrue(db.get(null,
            new DatabaseEntry("shouldNotFail".getBytes()),
            data,
            null) == OperationStatus.SUCCESS);
      assertTrue(new String(data.getData()).equals("shouldNotFailD"));

      assertTrue(db.get(null,
            new DatabaseEntry("shouldFail".getBytes()),
            data,
            null) == OperationStatus.NOTFOUND);

      assertTrue(db.get(null,
            new DatabaseEntry("shouldFail".getBytes()),
            data,
            null) == OperationStatus.NOTFOUND);

      assertTrue(db.get(null,
            new DatabaseEntry(keyStr.getBytes()),
            data,
            null) == OperationStatus.NOTFOUND);

      for (int i = --keyInt; i > 0; i--) {
    keyStr = Integer.toString(i);
    assertTrue(db.get(null,
          new DatabaseEntry(keyStr.getBytes()),
          data,
          null) == OperationStatus.SUCCESS);
    assertTrue(new String(data.getData()).equals("d" + keyStr));
      }

  } catch (Throwable T) {
      T.printStackTrace();
  }
    }

    private void doIOExceptionTest(boolean doRecovery)
  throws Throwable {

  Transaction txn = null;
  createDatabase(0);
  writeAndVerify(null, false, "k1", "d1", doRecovery);
  writeAndVerify(null, true, "k2", "d2", doRecovery);
  writeAndVerify(null, false, "k3", "d3", doRecovery);

  txn = env.beginTransaction(null, null);
  writeAndVerify(txn, false, "k4", "d4", false);
  txn.abort();
  verify(null, true, "k4", doRecovery);
  verify(null, false, "k1", doRecovery);
  verify(null, false, "k3", doRecovery);

  txn = env.beginTransaction(null, null);
  writeAndVerify(txn, false, "k4", "d4", false);
  txn.commit();
  verify(null, false, "k4", doRecovery);

  txn = env.beginTransaction(null, null);
  writeAndVerify(txn, true, "k5", "d5", false);
  /* Ensure that writes after IOExceptions don't succeed. */
  writeAndVerify(txn, false, "k5a", "d5a", false);
  txn.abort();
  verify(null, true, "k5", doRecovery);
  verify(null, true, "k5a", doRecovery);

  txn = env.beginTransaction(null, null);
  writeAndVerify(txn, false, "k6", "d6", false);
  writeAndVerify(txn, true, "k6a", "d6a", false);

  FileManager.IO_EXCEPTION_TESTING = true;
  try {
      txn.commit();
      fail("expected DatabaseException");
  } catch (DatabaseException DE) {
  }
  verify(null, true, "k6", doRecovery);
  verify(null, true, "k6a", doRecovery);

  txn = env.beginTransaction(null, null);
  writeAndVerify(txn, false, "k6", "d6", false);
  writeAndVerify(txn, true, "k6a", "d6a", false);
  writeAndVerify(txn, false, "k6b", "d6b", false);

  try {
      txn.commit();
  } catch (DatabaseException DE) {
      fail("expected success");
  }

  /*
   * k6a will still exist because the writeAndVerify didn't fail -- there
   * was no write.  The write happens at commit time.
   */
  verify(null, false, "k6", doRecovery);
  verify(null, false, "k6a", doRecovery);
  verify(null, false, "k6b", doRecovery);
    }

    private void writeAndVerify(Transaction txn,
        boolean throwIOException,
        String keyString,
        String dataString,
        boolean doRecovery)
  throws DatabaseException {

  //System.out.println("Key: " + keyString + " Data: " + dataString);
  DatabaseEntry key = new DatabaseEntry(keyString.getBytes());
  DatabaseEntry data = new DatabaseEntry(dataString.getBytes());
  FileManager.IO_EXCEPTION_TESTING = throwIOException;
  try {
      assertTrue(db.put(txn, key, data) == OperationStatus.SUCCESS);

      /*
       * We don't expect an IOException if we're in a transaction because
       * the put() only writes to the buffer, not the disk.  The write to
       * disk doesn't happen until the commit/abort.
       */
      if (throwIOException && txn == null) {
    fail("didn't catch DatabaseException.");
      }
  } catch (DatabaseException DE) {
      if (!throwIOException) {
    fail("caught DatabaseException.");
      }
  }
  verify(txn, throwIOException, keyString, doRecovery);
    }

    private void verify(Transaction txn,
      boolean expectFailure,
      String keyString,
      boolean doRecovery)
  throws DatabaseException {

  if (doRecovery) {
      db.close();
      forceCloseEnvOnly();
      createDatabase(0);
  }
  DatabaseEntry key = new DatabaseEntry(keyString.getBytes());
  DatabaseEntry returnedData = new DatabaseEntry();
  OperationStatus status =
      db.get(txn,
       key,
       returnedData,
       LockMode.DEFAULT);
  //System.out.println(keyString + " => " + status);
  assertTrue(status == ((expectFailure && txn == null) ?
            OperationStatus.NOTFOUND :
            OperationStatus.SUCCESS));
    }

    private void createDatabase(long cacheSize)
  throws DatabaseException {

        EnvironmentConfig envConfig = TestUtils.initEnvConfig();
        envConfig.setTransactional(true);
        envConfig.setAllowCreate(true);
  envConfig.setConfigParam
      (EnvironmentParams.NUM_LOG_BUFFERS.getName(), "2");
  envConfig.setConfigParam
      (EnvironmentParams.LOG_MEM_SIZE.getName(),
       EnvironmentParams.LOG_MEM_SIZE_MIN_STRING);
  if (cacheSize != 0) {
      envConfig.setCacheSize(cacheSize);
      envConfig.setConfigParam("java.util.logging.level", "OFF");
  }
  env = new Environment(envHome, envConfig);

        String databaseName = "ioexceptiondb";
        DatabaseConfig dbConfig = new DatabaseConfig();
        dbConfig.setAllowCreate(true);
        dbConfig.setSortedDuplicates(true);
  dbConfig.setTransactional(true);
        db = env.openDatabase(null, databaseName, dbConfig);
    }

    /* Force the environment to be closed even with outstanding handles.*/
    private void forceCloseEnvOnly()
  throws DatabaseException {

  /* Close w/out checkpointing, in order to exercise recovery better.*/
  try {
      DbInternal.envGetEnvironmentImpl(env).close(false);
  } catch (DatabaseException DE) {
      if (!FileManager.IO_EXCEPTION_TESTING) {
    throw DE;
      } else {
    /* Expect an exception from flushing the log manager. */
      }
  }
  env = null;
    }
}
TOP

Related Classes of com.sleepycat.je.log.IOExceptionTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.