00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00069
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
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
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
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
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
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
00231 testTxn(100,-1,50);
00232
00233
00234 expected.push_back(ExpectedRange(99,51));
00235 getLogicalTxn()->rollback(&svptId);
00236 BOOST_CHECK(expected.empty());
00237
00238 if (gap) {
00239
00240 testActions(40,200);
00241 expected.push_back(ExpectedRange(239,200));
00242 }
00243
00244
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
00264
00265 testTxn(100,75,50);
00266
00267
00268 expected.push_back(ExpectedRange(99,51));
00269 getLogicalTxn()->rollback(&svptId);
00270 BOOST_CHECK(expected.empty());
00271
00272
00273 testActions(40,200);
00274
00275 commit();
00276 SharedLogicalRecoveryLog pRecoveryLog = createRecoveryLog();
00277
00278
00279
00280
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