0001: /*
0002:
0003: Derby - Class org.apache.derbyTesting.unitTests.store.T_RecoverBadLog
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to You under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derbyTesting.unitTests.store;
0023:
0024: import org.apache.derbyTesting.unitTests.harness.T_Generic;
0025: import org.apache.derbyTesting.unitTests.harness.T_Fail;
0026: import org.apache.derbyTesting.unitTests.harness.UnitTest;
0027:
0028: import org.apache.derby.impl.store.raw.log.*;
0029:
0030: import org.apache.derby.iapi.services.context.ContextService;
0031: import org.apache.derby.iapi.services.context.ContextManager;
0032: import org.apache.derby.iapi.services.daemon.DaemonService;
0033: import org.apache.derby.iapi.services.monitor.Monitor;
0034: import org.apache.derby.iapi.services.locks.LockFactory;
0035: import org.apache.derby.iapi.services.io.Storable;
0036: import org.apache.derby.iapi.services.sanity.SanityManager;
0037: import org.apache.derby.iapi.reference.Property;
0038: import org.apache.derby.iapi.reference.EngineType;
0039: import org.apache.derby.iapi.services.property.PropertyUtil;
0040: import org.apache.derby.iapi.services.io.FormatableBitSet;
0041: import org.apache.derby.io.StorageRandomAccessFile;
0042:
0043: import org.apache.derby.iapi.error.StandardException;
0044:
0045: import org.apache.derby.iapi.store.raw.*;
0046:
0047: import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
0048:
0049: import org.apache.derby.iapi.store.access.Qualifier;
0050:
0051: import java.io.IOException;
0052: import java.io.RandomAccessFile;
0053: import java.io.File;
0054: import java.util.Properties;
0055:
0056: /**
0057: A implementation unit test for recovering log that has been damanged but salvagable.
0058:
0059: To run, create a derby.properties file in a new directory with the
0060: contents
0061:
0062: derby.module.test.recoverBadLog=org.apache.derbyTesting.unitTests.store.T_RecoverBadLog
0063:
0064: Execute in order
0065:
0066: To Test Bad Log due to partial write that are identified by checking the
0067: length in the beginning and end of the log record.
0068:
0069: java -DTestBadLogSetup=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0070: java -DTestBadLog1=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0071: java -DTestBadLog2=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0072: java -DTestBadLog3=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0073: java -DTestBadLog4=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0074: java -DTestBadLog5=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0075: java -DTestBadLog6=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0076: java -DTestBadLog7=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0077: java -DTestBadLog1=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0078:
0079: To Test Bad Log due to an incomplete out of order write that is identified
0080: by the checksum logic (simulated by explicitly corrupting a middle of a
0081: log record at the end of log file after it is written).
0082:
0083: java -DTestBadLogSetup=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0084: java -DTestBadLog1=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0085: java -DTestBadLog2=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0086: java -DTestBadLog3=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0087: java -DTestBadLog4=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0088: java -DTestBadLog5=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0089: java -DTestBadLog6=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0090: java -DTestBadLog7=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0091: java -DTestBadLog1=true -DTestBadChecksumLog=true org.apache.derbyTesting.unitTests.harness.UnitTestMain
0092:
0093:
0094: */
0095:
0096: public class T_RecoverBadLog extends T_Generic {
0097:
0098: private String testService = "BadLogTest";
0099:
0100: static final String REC_001 = "McLaren";
0101: static final String REC_002 = "Ferrari";
0102: static final String REC_003 = "Benetton";
0103: static final String REC_004 = "Prost";
0104: static final String REC_005 = "Tyrell";
0105: static final String REC_006 = "Derby, Natscape, Goatscape, the popular names";
0106: static final String REC_UNDO = "Lotus";
0107:
0108: static final String SP1 = "savepoint1";
0109: static final String SP2 = "savepoint2";
0110:
0111: private RandomAccessFile infofile = null;
0112:
0113: private boolean setup;
0114: private boolean test1;
0115: private boolean test2;
0116: private boolean test3;
0117: private boolean test4;
0118: private boolean test5;
0119: private boolean test6;
0120: private boolean test7;
0121: private boolean checksumTest;
0122:
0123: private String infoPath = "extinout/T_RecoverBadLog.info";
0124:
0125: private static final String TEST_BADLOG_SETUP = "TestBadLogSetup";
0126: private static final String TEST_BADLOG1 = "TestBadLog1";
0127: private static final String TEST_BADLOG2 = "TestBadLog2";
0128: private static final String TEST_BADLOG3 = "TestBadLog3";
0129: private static final String TEST_BADLOG4 = "TestBadLog4";
0130: private static final String TEST_BADLOG5 = "TestBadLog5";
0131: private static final String TEST_BADLOG6 = "TestBadLog6";
0132: private static final String TEST_BADLOG7 = "TestBadLog7";
0133:
0134: private static final String TEST_BAD_CHECKSUM_LOG = "TestBadChecksumLog";
0135:
0136: private static final String TEST_BADLOG_INFO = "TestBadLogInfo";
0137: private static final String TEST_BADCHECKSUMLOG_INFO = "TestBadChecksumLogInfo";
0138:
0139: RawStoreFactory factory;
0140: LockFactory lf;
0141: LogToFile logFactory;
0142: ContextService contextService;
0143: T_Util t_util;
0144:
0145: public T_RecoverBadLog() {
0146: super ();
0147: }
0148:
0149: /*
0150: ** Methods required by T_Generic
0151: */
0152:
0153: public String getModuleToTestProtocolName() {
0154: return RawStoreFactory.MODULE;
0155: }
0156:
0157: /**
0158: */
0159: private void getConfig() {
0160: String param;
0161:
0162: param = PropertyUtil.getSystemProperty(TEST_BADLOG_SETUP);
0163: setup = Boolean.valueOf(param).booleanValue();
0164:
0165: param = PropertyUtil.getSystemProperty(TEST_BADLOG1);
0166: test1 = Boolean.valueOf(param).booleanValue();
0167:
0168: param = PropertyUtil.getSystemProperty(TEST_BADLOG2);
0169: test2 = Boolean.valueOf(param).booleanValue();
0170:
0171: param = PropertyUtil.getSystemProperty(TEST_BADLOG3);
0172: test3 = Boolean.valueOf(param).booleanValue();
0173:
0174: param = PropertyUtil.getSystemProperty(TEST_BADLOG4);
0175: test4 = Boolean.valueOf(param).booleanValue();
0176:
0177: param = PropertyUtil.getSystemProperty(TEST_BADLOG5);
0178: test5 = Boolean.valueOf(param).booleanValue();
0179:
0180: param = PropertyUtil.getSystemProperty(TEST_BADLOG6);
0181: test6 = Boolean.valueOf(param).booleanValue();
0182:
0183: param = PropertyUtil.getSystemProperty(TEST_BADLOG7);
0184: test7 = Boolean.valueOf(param).booleanValue();
0185:
0186: param = PropertyUtil.getSystemProperty(TEST_BAD_CHECKSUM_LOG);
0187: checksumTest = Boolean.valueOf(param).booleanValue();
0188:
0189: if (checksumTest) {
0190: infoPath = "extinout/T_RecoverBadChecksumLog.info";
0191: testService = "BadChecksumLogTest";
0192: }
0193: }
0194:
0195: /**
0196: See T_Recovery for the general testing frame work
0197:
0198: @exception T_Fail Unexpected behaviour from the API
0199: */
0200: public void runTests() throws T_Fail {
0201:
0202: getConfig();
0203: int tests = 0;
0204: if (setup)
0205: tests++;
0206: if (test1)
0207: tests++;
0208: if (test2)
0209: tests++;
0210: if (test3)
0211: tests++;
0212: if (test4)
0213: tests++;
0214: if (test5)
0215: tests++;
0216: if (test6)
0217: tests++;
0218: if (test7)
0219: tests++;
0220:
0221: if (tests != 1)
0222: throw T_Fail
0223: .testFailMsg("One & only one of the bad log recovery test should be run");
0224:
0225: if (!SanityManager.DEBUG) {
0226: REPORT("recoverBadLog cannot be run on an insane server");
0227: return;
0228: }
0229:
0230: try {
0231: contextService = ContextService.getFactory();
0232:
0233: File ifile = new File(infoPath);
0234:
0235: //
0236: // no checkpoint log record in any of the log files - unless this value
0237: // is reset. LogToFile.TEST_LOG_SWITCH_LOG
0238: // this will cause recovery to switch log without checkpointing
0239: //
0240: SanityManager.DEBUG_SET(LogToFile.TEST_LOG_SWITCH_LOG);
0241:
0242: // don't want background checkpoint process to be running
0243: SanityManager.DEBUG_SET(DaemonService.DaemonOff);
0244:
0245: // see if we are testing encryption
0246: startParams = T_Util.setEncryptionParam(startParams);
0247:
0248: if (setup) // the first test cleans up and start from fresh
0249: {
0250: // remove the service directory to ensure a clean run
0251: REPORT("_______________________________________________________");
0252: REPORT("\n\t\tcleaning up database for recovering from bad logs");
0253: REPORT("_______________________________________________________");
0254:
0255: // don't automatic boot this service if it gets left around
0256: if (startParams == null)
0257: startParams = new Properties();
0258:
0259: startParams.put(Property.NO_AUTO_BOOT, Boolean.TRUE
0260: .toString());
0261: // remove the service directory to ensure a clean run
0262: startParams.put(Property.DELETE_ON_CREATE, Boolean.TRUE
0263: .toString());
0264:
0265: factory = (RawStoreFactory) Monitor
0266: .createPersistentService(
0267: getModuleToTestProtocolName(),
0268: testService, startParams);
0269: // create a database with nothing
0270:
0271: // delete the info file
0272: if (ifile.exists())
0273: ifile.delete();
0274:
0275: return; // don't run anything now
0276:
0277: } else // not setup, recover it
0278: {
0279: REPORT("_______________________________________________________");
0280:
0281: String message = "\n\t\tRunning bad log test ";
0282: if (checksumTest)
0283: message = "\n\t\tRunning bad checksum log test ";
0284: if (test1)
0285: REPORT(message + " 1");
0286: if (test2)
0287: REPORT(message + " 2");
0288: if (test3)
0289: REPORT(message + " 3");
0290: if (test4)
0291: REPORT(message + " 4");
0292: if (test5)
0293: REPORT(message + " 5");
0294: if (test6)
0295: REPORT(message + " 6");
0296: if (test7)
0297: REPORT(message + " 7");
0298:
0299: REPORT("_______________________________________________________");
0300:
0301: //if external input output files does not exist ,create one
0302: File ifdir = new File("extinout");
0303: if (!ifdir.exists())
0304: ifdir.mkdirs();
0305:
0306: try {
0307: // make sure it does exist
0308: infofile = new RandomAccessFile(ifile, "rw");
0309: } catch (IOException ioe) {
0310: System.out
0311: .println("Cannot write to temporary file "
0312: + infoPath
0313: + ". Please make sure it is correct, if not, please set the property "
0314: + "TestBadLogInfo=<where temp files should go>");
0315:
0316: throw T_Fail.exceptionFail(ioe);
0317: }
0318:
0319: if (!Monitor.startPersistentService(testService,
0320: startParams))
0321: throw T_Fail
0322: .testFailMsg("Monitor didn't know how to restart service: "
0323: + testService);
0324:
0325: factory = (RawStoreFactory) Monitor.findService(
0326: getModuleToTestProtocolName(), testService);
0327: logFactory = (LogToFile) Monitor.findServiceModule(
0328: factory, factory.getLogFactoryModule());
0329:
0330: }
0331: } catch (StandardException mse) {
0332: throw T_Fail.exceptionFail(mse);
0333: }
0334:
0335: if (factory == null) {
0336: throw T_Fail.testFailMsg(getModuleToTestProtocolName()
0337: + " service not started.");
0338: }
0339:
0340: lf = factory.getLockFactory();
0341: if (lf == null) {
0342: throw T_Fail.testFailMsg("LockFactory.MODULE not found");
0343: }
0344:
0345: // get a utility helper
0346: t_util = new T_Util(factory, lf, contextService);
0347:
0348: try {
0349:
0350: // these tests can be run in any order
0351: RTest1();
0352: RTest2();
0353: RTest3();
0354: RTest4();
0355: RTest5();
0356: RTest6();
0357: RTest7();
0358:
0359: if (test1)
0360: STest1();
0361:
0362: if (test2)
0363: STest2();
0364:
0365: if (test3)
0366: STest3();
0367:
0368: if (test4)
0369: STest4();
0370:
0371: if (test5)
0372: STest5();
0373:
0374: if (test6)
0375: STest6();
0376:
0377: if (test7)
0378: STest7();
0379:
0380: if (infofile != null)
0381: infofile.close();
0382:
0383: } catch (StandardException se) {
0384:
0385: throw T_Fail.exceptionFail(se);
0386: } catch (IOException ioe) {
0387: throw T_Fail.exceptionFail(ioe);
0388: }
0389: }
0390:
0391: private long find(long inkey) {
0392: if (infofile == null)
0393: return -1;
0394:
0395: try {
0396: infofile.seek(0);
0397: long key;
0398:
0399: while (true) {
0400: key = infofile.readLong();
0401: if (key == inkey) {
0402: long value = infofile.readLong();
0403: // System.out.println("found " + key + " " + value);
0404: return value;
0405: }
0406: infofile.readLong();
0407: }
0408: } catch (IOException ioe) {
0409: // System.out.println("key not found " + inkey);
0410: return -1;
0411: }
0412:
0413: }
0414:
0415: private long key(int test, int param) {
0416: long i = test;
0417: return ((i << 32) + param);
0418: }
0419:
0420: private void register(long key, long value) throws T_Fail {
0421: // System.out.println("registering " + key + " " + value);
0422: try {
0423: // go to the end
0424: infofile.seek(infofile.length());
0425: infofile.writeLong(key);
0426: infofile.writeLong(value);
0427: } catch (IOException ioe) {
0428: T_Fail.exceptionFail(ioe);
0429: }
0430: }
0431:
0432: /*
0433: * test1 manufactures a log with the following recoverable 'defects':
0434: * - a log file that only have a single large 1/2 written log record
0435: */
0436: protected void STest1() throws T_Fail, StandardException {
0437: Transaction t = t_util.t_startTransaction();
0438:
0439: ///////////////////////////////////////////
0440: //// log switch without checkpoint here ///
0441: ///////////////////////////////////////////
0442: factory.checkpoint();
0443:
0444: try {
0445: long cid = t_util.t_addContainer(t, 0);
0446: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0447:
0448: Page page = t_util.t_getPage(c,
0449: ContainerHandle.FIRST_PAGE_NUMBER);
0450:
0451: // make a really big record - fill 80% of the page
0452: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
0453:
0454: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
0455: String string1 = "01234567890123456789"; // 20 char string
0456: for (int i = 0; i < numcol; i++)
0457: bigrow.setColumn(i, string1);
0458:
0459: // if overhead is > 80%, then reduce the row size until it fits
0460: RecordHandle rh = null;
0461: while (numcol > 0) {
0462: try {
0463: rh = t_util.t_insert(page, bigrow);
0464: break;
0465: } catch (StandardException se) {
0466: bigrow.setColumn(--numcol, (String) null);
0467: }
0468: }
0469: if (numcol == 0)
0470: throw T_Fail
0471: .testFailMsg("cannot fit any column into the page");
0472:
0473: t_util.t_commit(t);
0474:
0475: // make a big log record - update row
0476: String string2 = "abcdefghijklmnopqrst"; // 20 char string
0477: for (int i = 0; i < numcol; i++)
0478: bigrow.setColumn(i, string2);
0479:
0480: c = t_util.t_openContainer(t, 0, cid, true);
0481: page = t_util.t_getPage(c,
0482: ContainerHandle.FIRST_PAGE_NUMBER);
0483:
0484: Page p2 = t_util.t_addPage(c); // do something so we get the beginXact log
0485: // record out of the way
0486: t_util.t_insert(p2, new T_RawStoreRow(REC_001));
0487:
0488: ///////////////////////////////////////////
0489: //// log switch without checkpoint here ///
0490: ///////////////////////////////////////////
0491: factory.checkpoint();
0492:
0493: //////////////////////////////////////////////////////////
0494: // writing approx 1/2 log record to the end of the log -
0495: // NO MORE LOG RECORD SHOULD BE WRITTEN,
0496: //////////////////////////////////////////////////////////
0497: if (!checksumTest) {
0498: SanityManager
0499: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
0500: System.setProperty(
0501: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
0502: Integer.toString(numcol * 20));
0503: }
0504:
0505: logFactory.flushAll();
0506:
0507: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
0508:
0509: if (checksumTest)
0510: simulateLogFileCorruption();
0511:
0512: ////////////////////////////////////////////////////////
0513:
0514: REPORT("badlog test1: cid = " + cid + " numcol " + numcol);
0515:
0516: register(key(1, 1), cid);
0517: register(key(1, 2), numcol);
0518: } finally {
0519: SanityManager
0520: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
0521: }
0522: }
0523:
0524: /*
0525: * test recovery of test 1
0526: */
0527: void RTest1() throws T_Fail, StandardException {
0528: long cid = find(key(1, 1));
0529: if (cid < 0) {
0530: REPORT("bad log test1 not run");
0531: return;
0532: }
0533: int numcol = (int) find(key(1, 2));
0534:
0535: Transaction t = t_util.t_startTransaction();
0536: try {
0537: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0538: Page page = t_util.t_getPage(c,
0539: ContainerHandle.FIRST_PAGE_NUMBER);
0540:
0541: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
0542: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
0543: for (int i = 0; i < optimisticNumcol; i++)
0544: bigrow.setColumn(i, (String) null);
0545:
0546: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
0547: (FetchDescriptor) null, false);
0548:
0549: Storable column;
0550: String string1 = "01234567890123456789"; // the original 20 char string
0551:
0552: for (int i = 0; i < numcol; i++) {
0553: column = bigrow.getStorableColumn(i);
0554: if (!(column.toString().equals(string1)))
0555: throw T_Fail.testFailMsg("Column " + i
0556: + " value incorrect, got :"
0557: + column.toString());
0558: }
0559: for (int i = numcol; i < optimisticNumcol; i++) {
0560: column = bigrow.getStorableColumn(i);
0561: if (!column.isNull())
0562: throw T_Fail.testFailMsg("Column " + i
0563: + " expect Null, got : "
0564: + column.toString());
0565: }
0566:
0567: REPORT("RTest1 passed");
0568:
0569: } finally {
0570: t_util.t_commit(t);
0571: t.close();
0572: }
0573: }
0574:
0575: /*
0576: * test2 manufactures a log with the following recoverable 'defects':
0577: * - a log file that ends with a large 1/2 written log record
0578: */
0579: protected void STest2() throws T_Fail, StandardException {
0580: Transaction t = t_util.t_startTransaction();
0581:
0582: try {
0583: long cid = t_util.t_addContainer(t, 0);
0584: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0585:
0586: Page page = t_util.t_getPage(c,
0587: ContainerHandle.FIRST_PAGE_NUMBER);
0588:
0589: // make a really big record - fill 80% of the page with 20 bytes row
0590: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
0591:
0592: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
0593: String string1 = "01234567890123456789"; // 20 char string
0594: for (int i = 0; i < numcol; i++)
0595: bigrow.setColumn(i, string1);
0596:
0597: // if overhead is > 80%, then reduce the row size until it fits
0598: RecordHandle rh = null;
0599: while (numcol > 0) {
0600: try {
0601: rh = t_util.t_insert(page, bigrow);
0602: break;
0603: } catch (StandardException se) {
0604: bigrow.setColumn(--numcol, (String) null);
0605: }
0606: }
0607: if (numcol == 0)
0608: throw T_Fail
0609: .testFailMsg("cannot fit any column into the page");
0610:
0611: rh = t_util.t_insert(page, bigrow);
0612:
0613: t_util.t_commit(t);
0614:
0615: // make a big log record - update row
0616: String string2 = "abcdefghijklmnopqrst"; // 20 char string
0617: for (int i = 0; i < numcol; i++)
0618: bigrow.setColumn(i, string2);
0619:
0620: c = t_util.t_openContainer(t, 0, cid, true);
0621: page = t_util.t_getPage(c,
0622: ContainerHandle.FIRST_PAGE_NUMBER);
0623:
0624: //////////////////////////////////////////////////////////
0625: // writing approx 1/2 log record to the end of the log -
0626: // NO MORE LOG RECORD SHOULD BE WRITTEN,
0627: //////////////////////////////////////////////////////////
0628: if (!checksumTest) {
0629: SanityManager
0630: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
0631: System.setProperty(
0632: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
0633: Integer.toString(numcol * 20));
0634: }
0635:
0636: logFactory.flushAll();
0637: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
0638:
0639: if (checksumTest)
0640: simulateLogFileCorruption();
0641:
0642: ////////////////////////////////////////////////////////
0643:
0644: REPORT("badlog test2: cid = " + cid + " numcol " + numcol);
0645:
0646: register(key(2, 1), cid);
0647: register(key(2, 2), numcol);
0648: } finally {
0649: SanityManager
0650: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
0651: }
0652: }
0653:
0654: /*
0655: * test recovery of test 2
0656: */
0657: void RTest2() throws T_Fail, StandardException {
0658: long cid = find(key(2, 1));
0659: if (cid < 0) {
0660: REPORT("bad log test2 not run");
0661: return;
0662: }
0663: int numcol = (int) find(key(2, 2));
0664:
0665: Transaction t = t_util.t_startTransaction();
0666: try {
0667: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
0668: Page page = t_util.t_getPage(c,
0669: ContainerHandle.FIRST_PAGE_NUMBER);
0670:
0671: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
0672: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
0673: for (int i = 0; i < optimisticNumcol; i++)
0674: bigrow.setColumn(i, (String) null);
0675:
0676: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
0677: (FetchDescriptor) null, false);
0678: Storable column;
0679: String string1 = "01234567890123456789"; // the original 20 char string
0680:
0681: for (int i = 0; i < numcol; i++) {
0682: column = bigrow.getStorableColumn(i);
0683: if (!(column.toString().equals(string1)))
0684: throw T_Fail.testFailMsg("Column " + i
0685: + " value incorrect, got :"
0686: + column.toString());
0687: }
0688: for (int i = numcol; i < optimisticNumcol; i++) {
0689: column = bigrow.getStorableColumn(i);
0690: if (!column.isNull())
0691: throw T_Fail.testFailMsg("Column " + i
0692: + " expect Null, got : "
0693: + column.toString());
0694: }
0695:
0696: REPORT("RTest2 passed");
0697:
0698: } finally {
0699: t_util.t_commit(t);
0700: t.close();
0701: }
0702: }
0703:
0704: /*
0705: * test3 manufactures a log with the following recoverable 'defects':
0706: * - a log with multiple files but no checkpoint log record
0707: * - a last log file with a paritally written log record at the end
0708: */
0709: protected void STest3() throws T_Fail, StandardException {
0710: int numtrans = 7;
0711: int numpages = 7;
0712: int i, j;
0713:
0714: // this is basically T_Recovery S203 with a couple of log switches
0715: try {
0716: T_TWC[] t = new T_TWC[numtrans];
0717: for (i = 0; i < numtrans; i++)
0718: t[i] = t_util.t_startTransactionWithContext();
0719:
0720: long[] cid = new long[numtrans];
0721: ContainerHandle[] c = new ContainerHandle[numtrans];
0722:
0723: for (i = 0; i < numtrans; i++) {
0724: cid[i] = t_util.t_addContainer(t[i], 0);
0725: t_util.t_commit(t[i]);
0726: c[i] = t_util.t_openContainer(t[i], 0, cid[i], true);
0727: }
0728:
0729: Page page[][] = new Page[numtrans][numpages];
0730: long pagenum[][] = new long[numtrans][numpages];
0731:
0732: for (i = 0; i < numtrans; i++) {
0733: for (j = 0; j < numpages; j++) {
0734: t[i].switchTransactionContext();
0735: page[i][j] = t_util.t_addPage(c[i]);
0736: pagenum[i][j] = page[i][j].getPageNumber();
0737: t[i].resetContext();
0738: }
0739: }
0740:
0741: // set up numtrans (at least 5) transactions, each with one
0742: // container and numpages pages. Do the following test:
0743: //
0744: // 1) insert 1 row onto each page
0745: // set savepoint SP1 on first transaction (t0)
0746: //
0747: // 2) update every rows
0748: // set savepoint SP1 on all other transactions
0749: //
0750: // 3) update every rows
0751: // set savepoint SP2 on all transactions
0752: //
0753: // 4) update every rows
0754: //
0755: // 5) rollback t0 to SP1
0756: //
0757: // check that only page[0][x] have been rolled back
0758: // past SP2
0759: //
0760: // 6) update every row
0761: // 7) rollback SP2 on all transaction except the first
0762: //
0763: // 8) update every rows
0764: // 9) rollback t0 to SP1
0765: //
0766: // 10) leave transactions in the following state
0767: // t0 - incomplete
0768: // t1 - abort
0769: // t2 - commit
0770: // t3 - incomplete
0771: // t4 - commit
0772: // any other transactions - incomplete
0773:
0774: //////////////////////// step 1 ////////////////////////
0775: RecordHandle[][] rh = new RecordHandle[numtrans][numpages];
0776: T_RawStoreRow row1 = new T_RawStoreRow(REC_001);
0777: for (i = 0; i < numtrans; i++)
0778: for (j = 0; j < numpages; j++) {
0779: t[i].switchTransactionContext();
0780: rh[i][j] = t_util.t_insert(page[i][j], row1);
0781: t[i].resetContext();
0782: }
0783:
0784: t[0].setSavePoint(SP1, null); // sp1
0785:
0786: //////////////////////// step 2 ////////////////////////
0787: T_RawStoreRow row2 = new T_RawStoreRow(REC_002);
0788: for (i = 0; i < numtrans; i++)
0789: for (j = 0; j < numpages; j++) {
0790: t[i].switchTransactionContext();
0791: page[i][j].update(rh[i][j], row2.getRow(),
0792: (FormatableBitSet) null);
0793: t[i].resetContext();
0794: }
0795:
0796: for (i = 1; i < numtrans; i++) // sp1
0797: {
0798: t[i].setSavePoint(SP1, null);
0799: }
0800:
0801: ///////////////////////////////////////////
0802: //// log switch without checkpoint here ///
0803: ///////////////////////////////////////////
0804: factory.checkpoint();
0805:
0806: //////////////////////// step 3 ////////////////////////
0807: T_RawStoreRow row3 = new T_RawStoreRow(REC_003);
0808: for (i = 0; i < numtrans; i++)
0809: for (j = 0; j < numpages; j++)
0810: page[i][j].update(rh[i][j], row3.getRow(),
0811: (FormatableBitSet) null);
0812:
0813: for (i = 0; i < numtrans; i++)
0814: t[i].setSavePoint(SP2, null); // sp2
0815:
0816: //////////////////////// step 4 ////////////////////////
0817: T_RawStoreRow row4 = new T_RawStoreRow(REC_004);
0818: for (i = 0; i < numtrans; i++) {
0819: t[i].switchTransactionContext();
0820:
0821: for (j = 0; j < numpages; j++)
0822: page[i][j].update(rh[i][j], row4.getRow(),
0823: (FormatableBitSet) null);
0824: t[i].resetContext();
0825: }
0826:
0827: //////////////////////// step 5 ////////////////////////
0828: // unlatch relavante pages
0829: t[0].switchTransactionContext();
0830:
0831: for (j = 0; j < numpages; j++)
0832: page[0][j].unlatch();
0833:
0834: t[0].rollbackToSavePoint(SP1, null); // step 5
0835:
0836: // relatch relavante pages
0837: for (j = 0; j < numpages; j++)
0838: page[0][j] = t_util.t_getPage(c[0], pagenum[0][j]);
0839:
0840: t[0].resetContext();
0841:
0842: ///////////////////////////////////////////
0843: //// log switch without checkpoint here ///
0844: ///////////////////////////////////////////
0845: factory.checkpoint();
0846:
0847: //////////////////////// check ////////////////////////
0848: for (i = 1; i < numtrans; i++) {
0849: t[i].switchTransactionContext();
0850: for (j = 0; j < numpages; j++)
0851: t_util.t_checkFetch(page[i][j], rh[i][j], REC_004);
0852: t[i].resetContext();
0853: }
0854:
0855: t[0].switchTransactionContext();
0856: for (j = 0; j < numpages; j++)
0857: t_util.t_checkFetch(page[0][j], rh[0][j], REC_001);
0858: t[0].resetContext();
0859:
0860: //////////////////////// step 6 ////////////////////////
0861: T_RawStoreRow row5 = new T_RawStoreRow(REC_005);
0862: for (i = 0; i < numtrans; i++) {
0863: t[i].switchTransactionContext();
0864: for (j = 0; j < numpages; j++)
0865: page[i][j].update(rh[i][j], row5.getRow(),
0866: (FormatableBitSet) null);
0867: t[i].resetContext();
0868: }
0869:
0870: //////////////////////// step 7 ////////////////////////
0871: for (i = 1; i < numtrans; i++) {
0872: t[i].switchTransactionContext();
0873:
0874: for (j = 0; j < numpages; j++)
0875: page[i][j].unlatch();
0876:
0877: t[i].rollbackToSavePoint(SP2, null);
0878:
0879: for (j = 0; j < numpages; j++)
0880: page[i][j] = t_util.t_getPage(c[i], pagenum[i][j]);
0881: t[i].resetContext();
0882: }
0883:
0884: //////////////////////// check ////////////////////////
0885: for (i = 1; i < numtrans; i++) {
0886: t[i].switchTransactionContext();
0887: for (j = 0; j < numpages; j++)
0888: t_util.t_checkFetch(page[i][j], rh[i][j], REC_003);
0889: t[i].resetContext();
0890: }
0891:
0892: t[0].switchTransactionContext();
0893: for (j = 0; j < numpages; j++)
0894: t_util.t_checkFetch(page[0][j], rh[0][j], REC_005);
0895:
0896: t[0].resetContext();
0897:
0898: ///////////////////////////////////////////
0899: //// log switch without checkpoint here ///
0900: ///////////////////////////////////////////
0901: factory.checkpoint();
0902:
0903: //////////////////////// step 8 ////////////////////////
0904: T_RawStoreRow row6 = new T_RawStoreRow(REC_006);
0905: for (i = 0; i < numtrans; i++) {
0906: t[i].switchTransactionContext();
0907: for (j = 0; j < numpages; j++)
0908: page[i][j].update(rh[i][j], row6.getRow(),
0909: (FormatableBitSet) null); // step 8
0910: t[i].resetContext();
0911: }
0912:
0913: //////////////////////// step 9 ////////////////////////
0914: // unlatch relavante pages
0915: t[0].switchTransactionContext();
0916: for (j = 0; j < numpages; j++)
0917: page[0][j].unlatch();
0918:
0919: t[0].rollbackToSavePoint(SP1, null);
0920:
0921: // relatch relevant pages
0922: for (j = 0; j < numpages; j++)
0923: page[0][j] = t_util.t_getPage(c[0], pagenum[0][j]);
0924:
0925: t[0].resetContext();
0926: //////////////////////// check ////////////////////////
0927: for (i = 1; i < numtrans; i++) {
0928: t[i].switchTransactionContext();
0929:
0930: for (j = 0; j < numpages; j++) {
0931: t_util.t_checkFetch(page[i][j], rh[i][j], REC_006);
0932: t_util.t_checkRecordCount(page[i][j], 1, 1);
0933: }
0934: t[i].resetContext();
0935: }
0936:
0937: t[0].switchTransactionContext();
0938: for (j = 0; j < numpages; j++) {
0939: t_util.t_checkFetch(page[0][j], rh[0][j], REC_001);
0940: t_util.t_checkRecordCount(page[0][j], 1, 1);
0941: }
0942: t[0].resetContext();
0943:
0944: //////////////////////// step 10 ////////////////////////
0945: // unlatch all pages
0946: for (i = 0; i < numtrans; i++) {
0947: t[i].switchTransactionContext();
0948: for (j = 0; j < numpages; j++)
0949: page[i][j].unlatch();
0950: t[i].resetContext();
0951: }
0952:
0953: // t[0] incomplete
0954: t_util.t_abort(t[1]);
0955: t_util.t_commit(t[2]);
0956: // t[3] incomplete
0957: t_util.t_commit(t[4]);
0958:
0959: // reopen containers 1, 2, and 4, where were closed when the
0960: // transaction terminated.
0961: c[1] = t_util.t_openContainer(t[1], 0, cid[1], false);
0962: c[2] = t_util.t_openContainer(t[2], 0, cid[2], false);
0963: c[4] = t_util.t_openContainer(t[4], 0, cid[4], false);
0964:
0965: //////////////////////// check ////////////////////////
0966: for (j = 0; j < numpages; j++) {
0967: t[0].switchTransactionContext();
0968: t_util.t_checkFetch(c[0], rh[0][j], REC_001);
0969: t[0].resetContext();
0970:
0971: // t[1] has been aborted
0972: // rh[1][j] (REC_001) is deleted
0973: t[1].switchTransactionContext();
0974: page[1][j] = t_util.t_getPage(c[1], pagenum[1][j]);
0975: t_util.t_checkRecordCount(page[1][j], 1, 0);
0976: t_util.t_checkFetchBySlot(page[1][j],
0977: Page.FIRST_SLOT_NUMBER, REC_001, true, false);
0978: page[1][j].unlatch();
0979: t[1].resetContext();
0980:
0981: t[2].switchTransactionContext();
0982: t_util.t_checkFetch(c[2], rh[2][j], REC_006);
0983: t[2].resetContext();
0984:
0985: t[3].switchTransactionContext();
0986: t_util.t_checkFetch(c[3], rh[3][j], REC_006);
0987: t[3].resetContext();
0988:
0989: t[4].switchTransactionContext();
0990: t_util.t_checkFetch(c[4], rh[4][j], REC_006);
0991: t[4].resetContext();
0992: }
0993:
0994: ///////////////////////////////////////////////////////////
0995: //// now write a 1/2 log record to the end of the log
0996: //////////////////////////////////////////////////////////
0997: t[3].switchTransactionContext();// this is going to be an
0998: // incomplete transaction
0999:
1000: // make a full page and then copy and purge it to another page
1001: Page badPage1 = t_util.t_addPage(c[3]);
1002: Page badPage2 = t_util.t_addPage(c[3]);
1003: T_RawStoreRow row;
1004: for (i = 0, row = new T_RawStoreRow("row at slot " + i); badPage1
1005: .spaceForInsert(); i++, row = new T_RawStoreRow(
1006: "row at slot " + i)) {
1007: if (t_util.t_insertAtSlot(badPage1, i, row,
1008: Page.INSERT_UNDO_WITH_PURGE) == null)
1009: break;
1010: }
1011:
1012: //////////////////////////////////////////////////////////
1013: // writing 200 bytes of the log record to the end of the log -
1014: // NO MORE LOG RECORD SHOULD BE WRITTEN,
1015: //////////////////////////////////////////////////////////
1016: if (!checksumTest) {
1017: SanityManager
1018: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1019: System.setProperty(
1020: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
1021: "200");
1022: }
1023: logFactory.flushAll();
1024:
1025: // RESOLVE:
1026: // copy and purge actually generates 2 log records, this is
1027: // actually not a good operation to use for this test. Just make
1028: // sure the first log record is > 400 or else the log will be hosed
1029: //
1030: badPage1.copyAndPurge(badPage2, 0, i, 0);
1031:
1032: t[3].resetContext();
1033:
1034: if (checksumTest)
1035: simulateLogFileCorruption();
1036:
1037: ////////////////////////////////////////////////////////
1038:
1039: REPORT("badlog test3: numtrans " + numtrans + " numpages "
1040: + numpages);
1041:
1042: for (i = 0; i < numtrans; i++) {
1043: register(key(3, i + 10), cid[i]);
1044:
1045: String str = "container " + i + ":"
1046: + find(key(3, i + 10)) + " pages: ";
1047:
1048: for (j = 0; j < numpages; j++) {
1049: str += pagenum[i][j] + " ";
1050: register(key(3, (i + 1) * 1000 + j), pagenum[i][j]);
1051: }
1052: REPORT("\t" + str);
1053: }
1054:
1055: register(key(3, 1), numtrans);
1056: register(key(3, 2), numpages);
1057: register(key(3, 3), badPage1.getPageNumber());
1058: register(key(3, 4), badPage2.getPageNumber());
1059:
1060: } finally {
1061: SanityManager
1062: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1063: }
1064: }
1065:
1066: /*
1067: * test recovery of test3
1068: */
1069: void RTest3() throws T_Fail, StandardException {
1070: int numtrans = (int) find(key(3, 1));
1071: if (numtrans < 0) {
1072: REPORT("bad log test3 not run");
1073: return;
1074: }
1075:
1076: int numpages = (int) find(key(3, 2));
1077: long badPagenum1 = find(key(3, 3)); // these two pages are involved in
1078: // the 1/2 written log record, make
1079: // sure they are not corrupted
1080: long badPagenum2 = find(key(3, 4));
1081:
1082: Transaction t = t_util.t_startTransaction();
1083:
1084: long[] cid = new long[numtrans];
1085: ContainerHandle[] c = new ContainerHandle[numtrans];
1086:
1087: long[][] pagenum = new long[numtrans][numpages];
1088: Page[][] page = new Page[numtrans][numpages];
1089:
1090: int i, j;
1091:
1092: for (i = 0; i < numtrans; i++) {
1093: cid[i] = find(key(3, i + 10));
1094:
1095: c[i] = t_util.t_openContainer(t, 0, cid[i], true);
1096:
1097: for (j = 0; j < numpages; j++) {
1098: pagenum[i][j] = find(key(3, (i + 1) * 1000 + j));
1099:
1100: page[i][j] = t_util.t_getPage(c[i], pagenum[i][j]);
1101: }
1102: }
1103:
1104: // transactions were left in the following state
1105: // t0 - incomplete (rolled back)
1106: // t1 - abort
1107: // t2 - commit
1108: // t3 - incomplete (rolled back)
1109: // t4 - commit
1110: // any other transactions - incomplete
1111: //
1112: // all the rolled back transaction should have a deleted REC_001
1113: // all the committed transactions should have a REC_006
1114: //
1115: try {
1116: for (j = 0; j < numpages; j++) {
1117: t_util.t_checkRecordCount(page[0][j], 1, 0);
1118: t_util.t_checkFetchBySlot(page[0][j],
1119: Page.FIRST_SLOT_NUMBER, REC_001, true, true);
1120:
1121: t_util.t_checkRecordCount(page[1][j], 1, 0);
1122: t_util.t_checkFetchBySlot(page[1][j],
1123: Page.FIRST_SLOT_NUMBER, REC_001, true, true);
1124:
1125: t_util.t_checkRecordCount(page[2][j], 1, 1);
1126: t_util.t_checkFetchBySlot(page[2][j],
1127: Page.FIRST_SLOT_NUMBER, REC_006, false, true);
1128:
1129: t_util.t_checkRecordCount(page[3][j], 1, 0);
1130: t_util.t_checkFetchBySlot(page[3][j],
1131: Page.FIRST_SLOT_NUMBER, REC_001, true, true);
1132:
1133: t_util.t_checkRecordCount(page[4][j], 1, 1);
1134: t_util.t_checkFetchBySlot(page[4][j],
1135: Page.FIRST_SLOT_NUMBER, REC_006, false, true);
1136: }
1137:
1138: // now check the two bad pages - they are in c[3] and should be empty
1139: Page badPage1 = t_util.t_getPage(c[3], badPagenum1);
1140: Page badPage2 = t_util.t_getPage(c[3], badPagenum2);
1141: t_util.t_checkRecordCount(badPage1, 0, 0);
1142: t_util.t_checkRecordCount(badPage2, 0, 0);
1143:
1144: REPORT("RTest3 passed: numtrans " + numtrans + " numpages "
1145: + numpages);
1146:
1147: for (i = 0; i < numtrans; i++) {
1148: String str = "container " + i + ":" + cid[i]
1149: + " pages: ";
1150: for (j = 0; j < numpages; j++)
1151: str += pagenum[i][j] + " ";
1152: REPORT("\t" + str);
1153: }
1154: } finally {
1155: t_util.t_commit(t);
1156: t.close();
1157: }
1158: }
1159:
1160: /*
1161: * test4 manufactures a log with the following recoverable 'defects':
1162: * - a log file that only has the partial log instance(7 bytes instead of 8
1163: * bytes writtne) of a log record written
1164: */
1165: protected void STest4() throws T_Fail, StandardException {
1166: Transaction t = t_util.t_startTransaction();
1167:
1168: try {
1169: long cid = t_util.t_addContainer(t, 0);
1170: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1171:
1172: Page page = t_util.t_getPage(c,
1173: ContainerHandle.FIRST_PAGE_NUMBER);
1174:
1175: // make a really big record - fill 80% of the page
1176: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1177:
1178: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
1179: String string1 = "01234567890123456789"; // 20 char string
1180: for (int i = 0; i < numcol; i++)
1181: bigrow.setColumn(i, string1);
1182:
1183: // if overhead is > 80%, then reduce the row size until it fits
1184: RecordHandle rh = null;
1185: while (numcol > 0) {
1186: try {
1187: rh = t_util.t_insert(page, bigrow);
1188: break;
1189: } catch (StandardException se) {
1190: bigrow.setColumn(--numcol, (String) null);
1191: }
1192: }
1193: if (numcol == 0)
1194: throw T_Fail
1195: .testFailMsg("cannot fit any column into the page");
1196:
1197: t_util.t_commit(t);
1198:
1199: // make a big log record - update row
1200: String string2 = "abcdefghijklmnopqrst"; // 20 char string
1201: for (int i = 0; i < numcol; i++)
1202: bigrow.setColumn(i, string2);
1203:
1204: c = t_util.t_openContainer(t, 0, cid, true);
1205: page = t_util.t_getPage(c,
1206: ContainerHandle.FIRST_PAGE_NUMBER);
1207:
1208: Page p2 = t_util.t_addPage(c); // do something so we get the beginXact log
1209: // record out of the way
1210: t_util.t_insert(p2, new T_RawStoreRow(REC_001));
1211:
1212: //////////////////////////////////////////////////////////
1213: // writing approx 1/2 of log record instance to the end of the log -
1214: // NO MORE LOG RECORD SHOULD BE WRITTEN,
1215: // Length 4 bytes + 7(8) bytes of log record instance
1216: //////////////////////////////////////////////////////////
1217: if (!checksumTest) {
1218: SanityManager
1219: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1220: System.setProperty(
1221: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
1222: Integer.toString(11));
1223: }
1224:
1225: logFactory.flushAll();
1226: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
1227:
1228: if (checksumTest)
1229: simulateLogFileCorruption();
1230:
1231: ////////////////////////////////////////////////////////
1232:
1233: REPORT("badlog test4: cid = " + cid + " numcol " + numcol);
1234:
1235: register(key(4, 1), cid);
1236: register(key(4, 2), numcol);
1237: } finally {
1238: SanityManager
1239: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1240: }
1241: }
1242:
1243: /*
1244: * test recovery of test 4
1245: */
1246: void RTest4() throws T_Fail, StandardException {
1247: long cid = find(key(4, 1));
1248: if (cid < 0) {
1249: REPORT("bad log test4 not run");
1250: return;
1251: }
1252: int numcol = (int) find(key(4, 2));
1253:
1254: Transaction t = t_util.t_startTransaction();
1255: try {
1256: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1257: Page page = t_util.t_getPage(c,
1258: ContainerHandle.FIRST_PAGE_NUMBER);
1259:
1260: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1261: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
1262: for (int i = 0; i < optimisticNumcol; i++)
1263: bigrow.setColumn(i, (String) null);
1264:
1265: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
1266: (FetchDescriptor) null, false);
1267:
1268: Storable column;
1269: String string1 = "01234567890123456789"; // the original 20 char string
1270:
1271: for (int i = 0; i < numcol; i++) {
1272: column = bigrow.getStorableColumn(i);
1273: if (!(column.toString().equals(string1)))
1274: throw T_Fail.testFailMsg("Column " + i
1275: + " value incorrect, got :"
1276: + column.toString());
1277: }
1278: for (int i = numcol; i < optimisticNumcol; i++) {
1279: column = bigrow.getStorableColumn(i);
1280: if (!column.isNull())
1281: throw T_Fail.testFailMsg("Column " + i
1282: + " expect Null, got : "
1283: + column.toString());
1284: }
1285:
1286: REPORT("RTest4 passed");
1287:
1288: } finally {
1289: t_util.t_commit(t);
1290: t.close();
1291: }
1292: }
1293:
1294: /*
1295: * test5 manufactures a log with the following recoverable 'defects':
1296: * - a log file that only has the partial log record length (3 bytes instead of 4
1297: * bytes writtne) of a log record written in the beginning
1298: */
1299: protected void STest5() throws T_Fail, StandardException {
1300: Transaction t = t_util.t_startTransaction();
1301:
1302: try {
1303: long cid = t_util.t_addContainer(t, 0);
1304: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1305:
1306: Page page = t_util.t_getPage(c,
1307: ContainerHandle.FIRST_PAGE_NUMBER);
1308:
1309: // make a really big record - fill 80% of the page
1310: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1311:
1312: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
1313: String string1 = "01234567890123456789"; // 20 char string
1314: for (int i = 0; i < numcol; i++)
1315: bigrow.setColumn(i, string1);
1316:
1317: // if overhead is > 80%, then reduce the row size until it fits
1318: RecordHandle rh = null;
1319: while (numcol > 0) {
1320: try {
1321: rh = t_util.t_insert(page, bigrow);
1322: break;
1323: } catch (StandardException se) {
1324: bigrow.setColumn(--numcol, (String) null);
1325: }
1326: }
1327: if (numcol == 0)
1328: throw T_Fail
1329: .testFailMsg("cannot fit any column into the page");
1330:
1331: t_util.t_commit(t);
1332:
1333: // make a big log record - update row
1334: String string2 = "abcdefghijklmnopqrst"; // 20 char string
1335: for (int i = 0; i < numcol; i++)
1336: bigrow.setColumn(i, string2);
1337:
1338: c = t_util.t_openContainer(t, 0, cid, true);
1339: page = t_util.t_getPage(c,
1340: ContainerHandle.FIRST_PAGE_NUMBER);
1341:
1342: Page p2 = t_util.t_addPage(c); // do something so we get the beginXact log
1343: // record out of the way
1344: t_util.t_insert(p2, new T_RawStoreRow(REC_001));
1345:
1346: //////////////////////////////////////////////////////////
1347: // writing approx 3 bytes of log record to the end of the log -
1348: // NO MORE LOG RECORD SHOULD BE WRITTEN,
1349: // Length 3 bytes (4) of log record length
1350: //////////////////////////////////////////////////////////
1351: if (!checksumTest) {
1352: SanityManager
1353: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1354: System.setProperty(
1355: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
1356: Integer.toString(3));
1357: }
1358: logFactory.flushAll();
1359:
1360: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
1361:
1362: if (checksumTest)
1363: simulateLogFileCorruption();
1364:
1365: ////////////////////////////////////////////////////////
1366:
1367: REPORT("badlog test5: cid = " + cid + " numcol " + numcol);
1368:
1369: register(key(5, 1), cid);
1370: register(key(5, 2), numcol);
1371: } finally {
1372: SanityManager
1373: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1374: }
1375: }
1376:
1377: /*
1378: * test recovery of test 5
1379: */
1380: void RTest5() throws T_Fail, StandardException {
1381: long cid = find(key(5, 1));
1382: if (cid < 0) {
1383: REPORT("bad log test5 not run");
1384: return;
1385: }
1386: int numcol = (int) find(key(5, 2));
1387:
1388: Transaction t = t_util.t_startTransaction();
1389: try {
1390: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1391: Page page = t_util.t_getPage(c,
1392: ContainerHandle.FIRST_PAGE_NUMBER);
1393:
1394: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1395: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
1396: for (int i = 0; i < optimisticNumcol; i++)
1397: bigrow.setColumn(i, (String) null);
1398:
1399: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
1400: (FetchDescriptor) null, false);
1401:
1402: Storable column;
1403: String string1 = "01234567890123456789"; // the original 20 char string
1404:
1405: for (int i = 0; i < numcol; i++) {
1406: column = bigrow.getStorableColumn(i);
1407: if (!(column.toString().equals(string1)))
1408: throw T_Fail.testFailMsg("Column " + i
1409: + " value incorrect, got :"
1410: + column.toString());
1411: }
1412: for (int i = numcol; i < optimisticNumcol; i++) {
1413: column = bigrow.getStorableColumn(i);
1414: if (!column.isNull())
1415: throw T_Fail.testFailMsg("Column " + i
1416: + " expect Null, got : "
1417: + column.toString());
1418: }
1419:
1420: REPORT("RTest5 passed");
1421:
1422: } finally {
1423: t_util.t_commit(t);
1424: t.close();
1425: }
1426: }
1427:
1428: /*
1429: * test6 manufactures a log with the following recoverable 'defects':
1430: * - a log file that only has the log record with partial data portion
1431: * written (approximately (1997/2 (data)+ 16(log records ov))) */
1432: protected void STest6() throws T_Fail, StandardException {
1433: Transaction t = t_util.t_startTransaction();
1434:
1435: try {
1436: long cid = t_util.t_addContainer(t, 0);
1437: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1438:
1439: Page page = t_util.t_getPage(c,
1440: ContainerHandle.FIRST_PAGE_NUMBER);
1441:
1442: // make a really big record - fill 80% of the page
1443: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1444:
1445: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
1446: String string1 = "01234567890123456789"; // 20 char string
1447: for (int i = 0; i < numcol; i++)
1448: bigrow.setColumn(i, string1);
1449:
1450: // if overhead is > 80%, then reduce the row size until it fits
1451: RecordHandle rh = null;
1452: while (numcol > 0) {
1453: try {
1454: rh = t_util.t_insert(page, bigrow);
1455: break;
1456: } catch (StandardException se) {
1457: bigrow.setColumn(--numcol, (String) null);
1458: }
1459: }
1460: if (numcol == 0)
1461: throw T_Fail
1462: .testFailMsg("cannot fit any column into the page");
1463:
1464: t_util.t_commit(t);
1465:
1466: // make a big log record - update row
1467: String string2 = "abcdefghijklmnopqrst"; // 20 char string
1468: for (int i = 0; i < numcol; i++)
1469: bigrow.setColumn(i, string2);
1470:
1471: c = t_util.t_openContainer(t, 0, cid, true);
1472: page = t_util.t_getPage(c,
1473: ContainerHandle.FIRST_PAGE_NUMBER);
1474:
1475: Page p2 = t_util.t_addPage(c); // do something so we get the beginXact log
1476: // record out of the way
1477: t_util.t_insert(p2, new T_RawStoreRow(REC_001));
1478:
1479: //////////////////////////////////////////////////////////
1480: // writing (1997/2 (data)+ 16(log records ov)) bytes of log record to the end of the log -
1481: // NO MORE LOG RECORD SHOULD BE WRITTEN,
1482: //////////////////////////////////////////////////////////
1483: if (!checksumTest) {
1484: SanityManager
1485: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1486: System.setProperty(
1487: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
1488: Integer.toString((1997 / 2) + 16));
1489: }
1490: logFactory.flushAll();
1491: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
1492:
1493: if (checksumTest)
1494: simulateLogFileCorruption();
1495:
1496: ////////////////////////////////////////////////////////
1497:
1498: REPORT("badlog test6: cid = " + cid + " numcol " + numcol);
1499:
1500: register(key(6, 1), cid);
1501: register(key(6, 2), numcol);
1502: } finally {
1503: SanityManager
1504: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1505: }
1506: }
1507:
1508: /*
1509: * test recovery of test 6
1510: */
1511: void RTest6() throws T_Fail, StandardException {
1512: long cid = find(key(6, 1));
1513: if (cid < 0) {
1514: REPORT("bad log test6 not run");
1515: return;
1516: }
1517: int numcol = (int) find(key(6, 2));
1518:
1519: Transaction t = t_util.t_startTransaction();
1520: try {
1521: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1522: Page page = t_util.t_getPage(c,
1523: ContainerHandle.FIRST_PAGE_NUMBER);
1524:
1525: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1526: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
1527: for (int i = 0; i < optimisticNumcol; i++)
1528: bigrow.setColumn(i, (String) null);
1529:
1530: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
1531: (FetchDescriptor) null, false);
1532:
1533: Storable column;
1534: String string1 = "01234567890123456789"; // the original 20 char string
1535:
1536: for (int i = 0; i < numcol; i++) {
1537: column = bigrow.getStorableColumn(i);
1538: if (!(column.toString().equals(string1)))
1539: throw T_Fail.testFailMsg("Column " + i
1540: + " value incorrect, got :"
1541: + column.toString());
1542: }
1543: for (int i = numcol; i < optimisticNumcol; i++) {
1544: column = bigrow.getStorableColumn(i);
1545: if (!column.isNull())
1546: throw T_Fail.testFailMsg("Column " + i
1547: + " expect Null, got : "
1548: + column.toString());
1549: }
1550:
1551: REPORT("RTest6 passed");
1552:
1553: } finally {
1554: t_util.t_commit(t);
1555: t.close();
1556: }
1557: }
1558:
1559: /*
1560: * test7 manufactures a log with the following recoverable 'defects':
1561: * - a log file that has the last log record with partial end length
1562: * written( 3 of 4 bytes). instead of (1997(data) + 16 (log records overhead)) write (1997 + 15)
1563: */
1564: protected void STest7() throws T_Fail, StandardException {
1565: Transaction t = t_util.t_startTransaction();
1566:
1567: try {
1568: long cid = t_util.t_addContainer(t, 0);
1569: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1570:
1571: Page page = t_util.t_getPage(c,
1572: ContainerHandle.FIRST_PAGE_NUMBER);
1573:
1574: // make a really big record - fill 80% of the page
1575: int numcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1576:
1577: T_RawStoreRow bigrow = new T_RawStoreRow(numcol);
1578: String string1 = "01234567890123456789"; // 20 char string
1579: for (int i = 0; i < numcol; i++)
1580: bigrow.setColumn(i, string1);
1581:
1582: // if overhead is > 80%, then reduce the row size until it fits
1583: RecordHandle rh = null;
1584: while (numcol > 0) {
1585: try {
1586: rh = t_util.t_insert(page, bigrow);
1587: break;
1588: } catch (StandardException se) {
1589: bigrow.setColumn(--numcol, (String) null);
1590: }
1591: }
1592: if (numcol == 0)
1593: throw T_Fail
1594: .testFailMsg("cannot fit any column into the page");
1595:
1596: t_util.t_commit(t);
1597:
1598: // make a big log record - update row
1599: String string2 = "abcdefghijklmnopqrst"; // 20 char string
1600: for (int i = 0; i < numcol; i++)
1601: bigrow.setColumn(i, string2);
1602:
1603: c = t_util.t_openContainer(t, 0, cid, true);
1604: page = t_util.t_getPage(c,
1605: ContainerHandle.FIRST_PAGE_NUMBER);
1606:
1607: Page p2 = t_util.t_addPage(c); // do something so we get the beginXact log
1608: // record out of the way
1609: t_util.t_insert(p2, new T_RawStoreRow(REC_001));
1610:
1611: //////////////////////////////////////////////////////////
1612: // writing only 3 bytes of end length of the log record to the end of the log -
1613: //i.e: instead of (1997(data) + 16 (log records overhead)) write (1997 + 15)
1614: // NO MORE LOG RECORD SHOULD BE WRITTEN,
1615: //////////////////////////////////////////////////////////
1616: if (!checksumTest) {
1617: SanityManager
1618: .DEBUG_SET(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1619: System.setProperty(
1620: LogToFile.TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES,
1621: Integer.toString(1997 + 15));
1622: }
1623: logFactory.flushAll();
1624: page.update(rh, bigrow.getRow(), (FormatableBitSet) null);
1625:
1626: if (checksumTest)
1627: simulateLogFileCorruption();
1628:
1629: ////////////////////////////////////////////////////////
1630:
1631: REPORT("badlog test7: cid = " + cid + " numcol " + numcol);
1632:
1633: register(key(7, 1), cid);
1634: register(key(7, 2), numcol);
1635: } finally {
1636: SanityManager
1637: .DEBUG_CLEAR(LogToFile.TEST_LOG_INCOMPLETE_LOG_WRITE);
1638: }
1639: }
1640:
1641: /*
1642: * test recovery of test 7
1643: */
1644: void RTest7() throws T_Fail, StandardException {
1645: long cid = find(key(6, 1));
1646: if (cid < 0) {
1647: REPORT("bad log test7 not run");
1648: return;
1649: }
1650: int numcol = (int) find(key(6, 2));
1651:
1652: Transaction t = t_util.t_startTransaction();
1653: try {
1654: ContainerHandle c = t_util.t_openContainer(t, 0, cid, true);
1655: Page page = t_util.t_getPage(c,
1656: ContainerHandle.FIRST_PAGE_NUMBER);
1657:
1658: int optimisticNumcol = (int) ((RawStoreFactory.PAGE_SIZE_MINIMUM * 8) / (10 * 20));
1659: T_RawStoreRow bigrow = new T_RawStoreRow(optimisticNumcol);
1660: for (int i = 0; i < optimisticNumcol; i++)
1661: bigrow.setColumn(i, (String) null);
1662:
1663: page.fetchFromSlot((RecordHandle) null, 0, bigrow.getRow(),
1664: (FetchDescriptor) null, false);
1665:
1666: Storable column;
1667: String string1 = "01234567890123456789"; // the original 20 char string
1668:
1669: for (int i = 0; i < numcol; i++) {
1670: column = bigrow.getStorableColumn(i);
1671: if (!(column.toString().equals(string1)))
1672: throw T_Fail.testFailMsg("Column " + i
1673: + " value incorrect, got :"
1674: + column.toString());
1675: }
1676: for (int i = numcol; i < optimisticNumcol; i++) {
1677: column = bigrow.getStorableColumn(i);
1678: if (!column.isNull())
1679: throw T_Fail.testFailMsg("Column " + i
1680: + " expect Null, got : "
1681: + column.toString());
1682: }
1683:
1684: REPORT("RTest7 passed");
1685:
1686: } finally {
1687: t_util.t_commit(t);
1688: t.close();
1689: }
1690: }
1691:
1692: /*
1693: * simulate log corruption to test the checksuming of log records.
1694: */
1695: private void simulateLogFileCorruption() throws T_Fail,
1696: StandardException {
1697: long filenum;
1698: long filepos;
1699: long amountOfLogWritten;
1700: LogCounter logInstant = (LogCounter) logFactory
1701: .getFirstUnflushedInstant();
1702: filenum = logInstant.getLogFileNumber();
1703: filepos = logInstant.getLogFilePosition();
1704: logFactory.flushAll();
1705: logInstant = (LogCounter) logFactory.getFirstUnflushedInstant();
1706: filenum = logInstant.getLogFileNumber();
1707: amountOfLogWritten = logInstant.getLogFilePosition() - filepos;
1708:
1709: // write some random garbage into the log file ,
1710: // purpose of doing this is to test that recovery works correctly when
1711: // log records in the end of a log file did not get wrtten completely
1712: // and in the correct order.
1713:
1714: try {
1715: StorageRandomAccessFile log = logFactory
1716: .getLogFileToSimulateCorruption(filenum);
1717:
1718: int noWrites = (int) amountOfLogWritten / 512;
1719: //mess up few bytes in every block of a 512 bytes.
1720: filepos += 512;
1721: java.util.Random r = new java.util.Random();
1722: for (int i = 0; i < noWrites; i++) {
1723: REPORT("corruptig log file : filenum " + filenum
1724: + " fileposition " + filepos);
1725: log.seek(filepos);
1726: log.writeInt(r.nextInt());
1727: filepos += 512;
1728:
1729: }
1730: log.sync(false);
1731: log.close();
1732: } catch (IOException ie) {
1733: throw T_Fail.exceptionFail(ie);
1734: }
1735:
1736: }
1737:
1738: }
|