LogicalTxnTest.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/test/LogicalTxnTest.cpp#12 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/txn/LogicalTxn.h"
00026 #include "fennel/txn/LogicalTxnLog.h"
00027 #include "fennel/txn/LogicalRecoveryLog.h"
00028 #include "fennel/txn/LogicalTxnStoredStructs.h"
00029 #include "fennel/txn/LogicalTxnParticipant.h"
00030 #include "fennel/txn/LogicalTxnParticipantFactory.h"
00031 #include "fennel/test/SegStorageTestBase.h"
00032 #include "fennel/common/ByteInputStream.h"
00033 #include "fennel/common/ByteOutputStream.h"
00034 #include "fennel/cache/Cache.h"
00035 
00036 #include <boost/test/test_tools.hpp>
00037 
00038 using namespace fennel;
00039 
00040 class LogicalTxnTest
00041     : virtual public SegStorageTestBase,
00042         public LogicalTxnParticipant,
00043         public LogicalTxnParticipantFactory
00044 {
00045     static const int participantDescription;
00046     static const LogicalActionType ACTION_TEST;
00047 
00048     SharedLogicalTxnLog pTxnLog;
00049     LogicalTxnLogCheckpointMemento firstCheckpointMemento;
00050     LogicalTxnLogCheckpointMemento intermediateCheckpointMemento;
00051     LogicalTxnLogCheckpointMemento finalCheckpointMemento;
00052     SavepointId svptId;
00053     PseudoUuid onlineUuid;
00054 
00055     typedef std::pair<int,int> ExpectedRange;
00056     std::vector<ExpectedRange> expected;
00057 
00058     void rollbackFull();
00059     void commit();
00060     void checkpointTxnLog(LogicalTxnLogCheckpointMemento &);
00061     SharedLogicalRecoveryLog createRecoveryLog();
00062 
00063 public:
00064     explicit LogicalTxnTest()
00065     {
00066         onlineUuid.generateInvalid();
00067 
00068         // TODO jvs 26-Oct-2007:  need multi-threading tests,
00069         // e.g. for FNL-68
00070 
00071         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testTxnIdSequence);
00072         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testRollbackEmpty);
00073         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testRollbackShort);
00074         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testRollbackLong);
00075         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testRollbackSavepointNoGap);
00076         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testRollbackSavepointGap);
00077         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointCommitSavepoint);
00078         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCommitEmpty);
00079         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCommitShort);
00080         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCommitLong);
00081         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointCommitEmpty);
00082         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointCommitShort);
00083         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointCommitLong);
00084         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointRollbackShort);
00085         FENNEL_UNIT_TEST_CASE(LogicalTxnTest,testCheckpointRollbackLong);
00086     }
00087 
00088     void testCaseSetUp()
00089     {
00090         expected.clear();
00091     }
00092 
00093     void testTxn(int nActions,int iCheckpoint = -1,int iSvpt = -1);
00094     void testActions(int nActions,int iFirst);
00095 
00096     void testRollback(
00097         int nActions,
00098         bool checkpoint = false);
00099     void testTxnIdSequence();
00100     void testRollbackEmpty();
00101     void testRollbackShort();
00102     void testRollbackLong();
00103 
00104     void testRollbackSavepointNoGap();
00105     void testRollbackSavepointGap();
00106     void testRollbackSavepoint(bool gap);
00107     void testCheckpointCommitSavepoint();
00108 
00109     void testCommit(int nActions,bool checkpoint = false);
00110     void testCommitEmpty();
00111     void testCommitShort();
00112     void testCommitLong();
00113     void testCheckpointCommitEmpty();
00114     void testCheckpointCommitShort();
00115     void testCheckpointCommitLong();
00116     void testCheckpointRollbackShort();
00117     void testCheckpointRollbackLong();
00118 
00119     // implement LogicalTxnParticipant
00120     virtual LogicalTxnClassId getParticipantClassId() const;
00121     virtual void describeParticipant(ByteOutputStream &logStream);
00122     virtual void redoLogicalAction(
00123         LogicalActionType actionType,
00124         ByteInputStream &logStream);
00125     virtual void undoLogicalAction(
00126         LogicalActionType actionType,
00127         ByteInputStream &logStream);
00128 
00129     // implement LogicalTxnParticipantFactory
00130     virtual SharedLogicalTxnParticipant loadParticipant(
00131         LogicalTxnClassId classId,
00132         ByteInputStream &logStream);
00133 };
00134 
00135 const int LogicalTxnTest::participantDescription = 42;
00136 const LogicalActionType LogicalTxnTest::ACTION_TEST = 1;
00137 
00138 LogicalTxnClassId LogicalTxnTest::getParticipantClassId() const
00139 {
00140     return LogicalTxnClassId(0x83f6b9edfe168b93LL);
00141 }
00142 
00143 void LogicalTxnTest::describeParticipant(ByteOutputStream &logStream)
00144 {
00145     int x = participantDescription;
00146     logStream.writeValue(x);
00147 }
00148 
00149 void LogicalTxnTest::checkpointTxnLog(
00150     LogicalTxnLogCheckpointMemento &memento)
00151 {
00152     pTxnLog->checkpoint(memento);
00153     pTxnLog->deallocateCheckpointedLog(memento);
00154 }
00155 
00156 void LogicalTxnTest::undoLogicalAction(
00157     LogicalActionType actionType,
00158     ByteInputStream &logStream)
00159 {
00160     // TODO:  symbolic const
00161     BOOST_CHECK_EQUAL(actionType,ACTION_TEST);
00162     int i;
00163     logStream.readValue(i);
00164     BOOST_CHECK(!expected.empty());
00165     ExpectedRange &range = expected.front();
00166     BOOST_CHECK_EQUAL(i,range.first);
00167     range.first--;
00168     if (range.first < range.second) {
00169         expected.erase(expected.begin());
00170     }
00171 }
00172 
00173 void LogicalTxnTest::redoLogicalAction(
00174     LogicalActionType actionType,
00175     ByteInputStream &logStream)
00176 {
00177     // TODO:  symbolic const
00178     BOOST_CHECK_EQUAL(actionType,ACTION_TEST);
00179     int i;
00180     logStream.readValue(i);
00181     BOOST_CHECK(!expected.empty());
00182     ExpectedRange &range = expected.front();
00183     BOOST_CHECK_EQUAL(i,range.first);
00184     range.first++;
00185     if (range.first > range.second) {
00186         expected.erase(expected.begin());
00187     }
00188 }
00189 
00190 void LogicalTxnTest::testTxnIdSequence()
00191 {
00192     testTxn(1);
00193     TxnId id1 = getLogicalTxn()->getTxnId();
00194     SharedLogicalTxn pTxn2 = pTxnLog->newLogicalTxn(pCache);
00195     TxnId id2 = pTxn2->getTxnId();
00196     pTxn2->commit();
00197     pTxn2.reset();
00198     commit();
00199     // TxnId reflects start order, not commit order
00200     BOOST_CHECK(id2 > id1);
00201 }
00202 
00203 void LogicalTxnTest::testRollbackEmpty()
00204 {
00205     testRollback(0);
00206 }
00207 
00208 void LogicalTxnTest::testRollbackShort()
00209 {
00210     testRollback(10);
00211 }
00212 
00213 void LogicalTxnTest::testRollbackLong()
00214 {
00215     testRollback(10000);
00216 }
00217 
00218 void LogicalTxnTest::testRollbackSavepointNoGap()
00219 {
00220     testRollbackSavepoint(false);
00221 }
00222 
00223 void LogicalTxnTest::testRollbackSavepointGap()
00224 {
00225     testRollbackSavepoint(true);
00226 }
00227 
00228 void LogicalTxnTest::testRollbackSavepoint(bool gap)
00229 {
00230     // log actions 0 through 99, creating a savepoint after 50
00231     testTxn(100,-1,50);
00232 
00233     // rollback 99 through 51
00234     expected.push_back(ExpectedRange(99,51));
00235     getLogicalTxn()->rollback(&svptId);
00236     BOOST_CHECK(expected.empty());
00237 
00238     if (gap) {
00239         // log 40 new actions (200 through 239)
00240         testActions(40,200);
00241         expected.push_back(ExpectedRange(239,200));
00242     }
00243 
00244     // roll everything back
00245     expected.push_back(ExpectedRange(50,0));
00246     rollbackFull();
00247 }
00248 
00249 SharedLogicalRecoveryLog LogicalTxnTest::createRecoveryLog()
00250 {
00251     SegmentAccessor segmentAccessor(pLinearSegment,pCache);
00252     SharedLogicalRecoveryLog pRecoveryLog =
00253         LogicalRecoveryLog::newLogicalRecoveryLog(
00254             *this,
00255             segmentAccessor,
00256             onlineUuid,
00257             pSegmentFactory);
00258     return pRecoveryLog;
00259 }
00260 
00261 void LogicalTxnTest::testCheckpointCommitSavepoint()
00262 {
00263     // log actions 0 through 99, checkpointing after 75 and creating a
00264     // savepoint after 50
00265     testTxn(100,75,50);
00266 
00267     // rollback 99 through 51
00268     expected.push_back(ExpectedRange(99,51));
00269     getLogicalTxn()->rollback(&svptId);
00270     BOOST_CHECK(expected.empty());
00271 
00272     // log 40 new actions (200 through 239)
00273     testActions(40,200);
00274 
00275     commit();
00276     SharedLogicalRecoveryLog pRecoveryLog = createRecoveryLog();
00277 
00278     // recovery should first see 76 through 99 (redo),
00279     // then 99 through 51 (undo),
00280     // then 200 through 239 (redo)
00281     expected.push_back(ExpectedRange(76,99));
00282     expected.push_back(ExpectedRange(99,51));
00283     expected.push_back(ExpectedRange(200,239));
00284     pRecoveryLog->recover(intermediateCheckpointMemento);
00285     BOOST_CHECK(expected.empty());
00286     assert(pRecoveryLog.unique());
00287 }
00288 
00289 void LogicalTxnTest::testCheckpointRollbackShort()
00290 {
00291     testRollback(10,true);
00292 }
00293 
00294 void LogicalTxnTest::testCheckpointRollbackLong()
00295 {
00296     testRollback(10000,true);
00297 }
00298 
00299 void LogicalTxnTest::testCommitEmpty()
00300 {
00301     testCommit(0);
00302 }
00303 
00304 void LogicalTxnTest::testCommitShort()
00305 {
00306     testCommit(10);
00307 }
00308 
00309 void LogicalTxnTest::testCommitLong()
00310 {
00311     testCommit(10000);
00312 }
00313 
00314 void LogicalTxnTest::testCheckpointCommitEmpty()
00315 {
00316     testCommit(0,true);
00317 }
00318 
00319 void LogicalTxnTest::testCheckpointCommitShort()
00320 {
00321     testCommit(10,true);
00322 }
00323 
00324 void LogicalTxnTest::testCheckpointCommitLong()
00325 {
00326     testCommit(10000,true);
00327 }
00328 
00329 void LogicalTxnTest::testRollback(
00330     int nActions,
00331     bool checkpoint)
00332 {
00333     int iCheckpoint = checkpoint ? (nActions / 2) : -1;
00334     testTxn(nActions,iCheckpoint);
00335     if (checkpoint) {
00336         SharedLogicalRecoveryLog pRecoveryLog = createRecoveryLog();
00337         expected.push_back(ExpectedRange(iCheckpoint,0));
00338         pRecoveryLog->recover(intermediateCheckpointMemento);
00339         BOOST_CHECK(expected.empty());
00340         assert(pRecoveryLog.unique());
00341     }
00342     if (nActions) {
00343         expected.push_back(ExpectedRange(nActions - 1, 0));
00344     }
00345     rollbackFull();
00346 }
00347 
00348 void LogicalTxnTest::rollbackFull()
00349 {
00350     getLogicalTxn()->rollback();
00351     BOOST_CHECK(expected.empty());
00352     checkpointTxnLog(finalCheckpointMemento);
00353     assert(pTxnLog.unique());
00354     pTxnLog.reset();
00355 }
00356 
00357 void LogicalTxnTest::commit()
00358 {
00359     getLogicalTxn()->commit();
00360     checkpointTxnLog(finalCheckpointMemento);
00361     assert(pTxnLog.unique());
00362     pTxnLog.reset();
00363 }
00364 
00365 void LogicalTxnTest::testCommit(int nActions,bool checkpoint)
00366 {
00367     int iCheckpoint = checkpoint ? (nActions / 2) : -1;
00368     testTxn(nActions,iCheckpoint);
00369     commit();
00370 
00371     SharedLogicalRecoveryLog pRecoveryLog = createRecoveryLog();
00372     if (checkpoint) {
00373         if (nActions) {
00374             expected.push_back(ExpectedRange(iCheckpoint + 1, nActions - 1));
00375         }
00376         pRecoveryLog->recover(intermediateCheckpointMemento);
00377     } else {
00378         if (nActions) {
00379             expected.push_back(ExpectedRange(0, nActions - 1));
00380         }
00381         pRecoveryLog->recover(firstCheckpointMemento);
00382     }
00383     BOOST_CHECK(expected.empty());
00384     assert(pRecoveryLog.unique());
00385 }
00386 
00387 void LogicalTxnTest::testTxn(int nActions,int iCheckpoint,int iSvpt)
00388 {
00389     openStorage(DeviceMode::createNew);
00390     SegmentAccessor segmentAccessor(pLinearSegment,pCache);
00391     pTxnLog = LogicalTxnLog::newLogicalTxnLog(
00392         segmentAccessor,onlineUuid,pSegmentFactory);
00393     checkpointTxnLog(firstCheckpointMemento);
00394     SharedLogicalTxn pTxn = pTxnLog->newLogicalTxn(pCache);
00395     pTxn->addParticipant(
00396         boost::dynamic_pointer_cast<LogicalTxnParticipant>(
00397             shared_from_this()));
00398     for (int i = 0; i < nActions; ++i) {
00399         ByteOutputStream &logStream =
00400             getLogicalTxn()->beginLogicalAction(*this,ACTION_TEST);
00401         logStream.writeValue(i);
00402         getLogicalTxn()->endLogicalAction();
00403         if (i == iCheckpoint) {
00404             checkpointTxnLog(intermediateCheckpointMemento);
00405         }
00406         if (i == iSvpt) {
00407             svptId = getLogicalTxn()->createSavepoint();
00408         }
00409     }
00410     if (!nActions && !iCheckpoint) {
00411         checkpointTxnLog(intermediateCheckpointMemento);
00412     }
00413 }
00414 
00415 void LogicalTxnTest::testActions(int nActions,int iFirst)
00416 {
00417     for (int i = 0; i < nActions; ++i) {
00418         ByteOutputStream &logStream =
00419             getLogicalTxn()->beginLogicalAction(*this,ACTION_TEST);
00420         int x = iFirst + i;
00421         logStream.writeValue(x);
00422         getLogicalTxn()->endLogicalAction();
00423     }
00424 }
00425 
00426 SharedLogicalTxnParticipant LogicalTxnTest::loadParticipant(
00427     LogicalTxnClassId classId,
00428     ByteInputStream &logStream)
00429 {
00430     BOOST_CHECK_EQUAL(classId,getParticipantClassId());
00431     int x;
00432     logStream.readValue(x);
00433     BOOST_CHECK_EQUAL(x,participantDescription);
00434     return boost::dynamic_pointer_cast<LogicalTxnParticipant>(
00435         shared_from_this());
00436 }
00437 
00438 FENNEL_UNIT_TEST_SUITE(LogicalTxnTest);
00439 
00440 // End LogicalTxnTest.cpp

Generated on Mon Jun 22 04:00:20 2009 for Fennel by  doxygen 1.5.1