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/test/TestBase.h"
00026 #include "fennel/db/Database.h"
00027 #include "fennel/cache/Cache.h"
00028 #include "fennel/cache/CacheParams.h"
00029 #include "fennel/tuple/StandardTypeDescriptor.h"
00030 #include "fennel/segment/Segment.h"
00031 #include "fennel/txn/LogicalTxn.h"
00032 #include "fennel/txn/LogicalTxnLog.h"
00033 #include "fennel/txn/LogicalTxnParticipant.h"
00034 #include "fennel/txn/LogicalTxnParticipantFactory.h"
00035 #include "fennel/common/ByteInputStream.h"
00036 #include "fennel/common/ByteOutputStream.h"
00037 #include "fennel/segment/SegPageLock.h"
00038
00039 #include <boost/test/test_tools.hpp>
00040
00041 using namespace fennel;
00042
00043 class DatabaseTest
00044 : virtual public TestBase,
00045 public LogicalTxnParticipant,
00046 public LogicalTxnParticipantFactory
00047 {
00048 static const LogicalActionType ACTION_INCREMENT;
00049
00050 static const LogicalActionType ACTION_INCREMENT_FORCE;
00051
00052 struct TestNode : public StoredNode
00053 {
00054 static const MagicNumber MAGIC_NUMBER = 0xa496c71bff0d41bdLL;
00055
00056 uint x;
00057 };
00058
00059 typedef SegNodeLock<TestNode> TestPageLock;
00060
00061 SharedCache pCache;
00062 SharedDatabase pDatabase;
00063 PageId persistentPageId;
00064
00065 void loadDatabase();
00066 void executeIncrementAction(int i);
00067 void executeIncrementAction(int i, LogicalActionType action);
00068 void executeIncrementTxn(int i);
00069 void executeCheckpointedTxn(
00070 int i,int j,bool commit,CheckpointType = CHECKPOINT_FLUSH_ALL);
00071 void verifyData(uint x);
00072 PageId writeData(uint x);
00073 void addTxnParticipant(SharedLogicalTxn);
00074
00075 public:
00076 explicit DatabaseTest()
00077 {
00078 configMap.setStringParam(
00079 Database::paramDatabaseDir,".");
00080 configMap.setStringParam(
00081 "databaseInitSize","1000");
00082 configMap.setStringParam(
00083 "tempInitSize","1000");
00084 configMap.setStringParam(
00085 "databaseShadowLogInitSize","1000");
00086 configMap.setStringParam(
00087 "databaseTxnLogInitSize","1000");
00088
00089 CacheParams cacheParams;
00090 cacheParams.readConfig(configMap);
00091 pCache = Cache::newCache(cacheParams);
00092
00093
00094
00095
00096 FENNEL_UNIT_TEST_CASE(DatabaseTest,testCreateEmpty);
00097 FENNEL_UNIT_TEST_CASE(DatabaseTest,testLoadEmpty);
00098 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverEmpty);
00099 FENNEL_UNIT_TEST_CASE(DatabaseTest,testCreateData);
00100 FENNEL_UNIT_TEST_CASE(DatabaseTest,testLoadData);
00101 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverDataWithFlush);
00102 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverDataWithoutFlush);
00103 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverDataFromCheckpoint);
00104 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverDataFromFuzzyCheckpoint);
00105 FENNEL_UNIT_TEST_CASE(DatabaseTest,testRecoverDataFromRollback);
00106
00107 FENNEL_UNIT_TEST_CASE(DatabaseTest,testForceTxns);
00108 }
00109
00110 virtual ~DatabaseTest()
00111 {
00112 }
00113
00114 virtual void testCaseTearDown()
00115 {
00116 pDatabase.reset();
00117 }
00118
00119 void testCreateEmpty();
00120 void testLoadEmpty();
00121 void testRecoverEmpty();
00122
00123 void testCreateData();
00124 void testLoadData();
00125 void testRecoverData(bool);
00126 void testRecoverDataFromCheckpoint(CheckpointType);
00127 void testRecoverDataFromCheckpoint();
00128 void testRecoverDataFromFuzzyCheckpoint();
00129 void testRecoverDataFromRollback();
00130 void testRecoverDataWithFlush();
00131 void testRecoverDataWithoutFlush();
00132 void testForceTxns();
00133
00134 void executeForceTxn();
00135
00136
00137 virtual LogicalTxnClassId getParticipantClassId() const;
00138 virtual void describeParticipant(ByteOutputStream &logStream);
00139 virtual void redoLogicalAction(
00140 LogicalActionType actionType,
00141 ByteInputStream &logStream);
00142 virtual void undoLogicalAction(
00143 LogicalActionType actionType,
00144 ByteInputStream &logStream);
00145
00146
00147 virtual SharedLogicalTxnParticipant loadParticipant(
00148 LogicalTxnClassId classId,
00149 ByteInputStream &logStream);
00150 };
00151
00152 const LogicalActionType DatabaseTest::ACTION_INCREMENT = 1;
00153
00154 const LogicalActionType DatabaseTest::ACTION_INCREMENT_FORCE = 2;
00155
00156 void DatabaseTest::testCreateEmpty()
00157 {
00158 pDatabase = Database::newDatabase(
00159 pCache,
00160 configMap,
00161 DeviceMode::createNew,
00162 shared_from_this());
00163 BOOST_CHECK(!pDatabase->isRecoveryRequired());
00164 }
00165
00166 void DatabaseTest::testCreateData()
00167 {
00168 testCreateEmpty();
00169 persistentPageId = writeData(0);
00170 pDatabase->checkpointImpl();
00171 executeIncrementTxn(5);
00172 }
00173
00174 void DatabaseTest::testLoadEmpty()
00175 {
00176 loadDatabase();
00177 BOOST_CHECK(!pDatabase->isRecoveryRequired());
00178 }
00179
00180 void DatabaseTest::testLoadData()
00181 {
00182 testLoadEmpty();
00183 verifyData(5);
00184 }
00185
00186 void DatabaseTest::testRecoverEmpty()
00187 {
00188 testCreateEmpty();
00189
00190
00191 pDatabase->checkpointImpl();
00192 pDatabase->checkpointImpl(CHECKPOINT_DISCARD);
00193 BOOST_CHECK(pDatabase->isRecoveryRequired());
00194 pDatabase.reset();
00195 loadDatabase();
00196 BOOST_CHECK(pDatabase->isRecoveryRequired());
00197 pDatabase->recover(*this);
00198 }
00199
00200 void DatabaseTest::testRecoverDataWithoutFlush()
00201 {
00202 testRecoverData(false);
00203 }
00204
00205 void DatabaseTest::testRecoverDataWithFlush()
00206 {
00207 testRecoverData(true);
00208 }
00209
00210 void DatabaseTest::testRecoverData(bool flush)
00211 {
00212 testCreateData();
00213 executeIncrementTxn(10);
00214 executeIncrementTxn(30);
00215 if (flush) {
00216 pDatabase->getDataSegment()->checkpoint();
00217 }
00218 pDatabase->checkpointImpl(CHECKPOINT_DISCARD);
00219 BOOST_CHECK(pDatabase->isRecoveryRequired());
00220 pDatabase.reset();
00221 loadDatabase();
00222 BOOST_CHECK(pDatabase->isRecoveryRequired());
00223 pDatabase->recover(*this);
00224 verifyData(45);
00225 }
00226
00227 void DatabaseTest::testRecoverDataFromCheckpoint(CheckpointType checkpointType)
00228 {
00229 testCreateData();
00230 executeIncrementTxn(10);
00231 executeCheckpointedTxn(25,70,true,checkpointType);
00232 pDatabase->checkpointImpl(CHECKPOINT_DISCARD);
00233 BOOST_CHECK(pDatabase->isRecoveryRequired());
00234 pDatabase.reset();
00235 loadDatabase();
00236 BOOST_CHECK(pDatabase->isRecoveryRequired());
00237 pDatabase->recover(*this);
00238 verifyData(110);
00239 }
00240
00241 void DatabaseTest::testRecoverDataFromCheckpoint()
00242 {
00243 testRecoverDataFromCheckpoint(CHECKPOINT_FLUSH_ALL);
00244 }
00245
00246 void DatabaseTest::testRecoverDataFromFuzzyCheckpoint()
00247 {
00248 testRecoverDataFromCheckpoint(CHECKPOINT_FLUSH_FUZZY);
00249 }
00250
00251 void DatabaseTest::testRecoverDataFromRollback()
00252 {
00253 testCreateData();
00254 executeIncrementTxn(10);
00255 executeCheckpointedTxn(25,70,false);
00256 pDatabase->checkpointImpl(CHECKPOINT_DISCARD);
00257 BOOST_CHECK(pDatabase->isRecoveryRequired());
00258 pDatabase.reset();
00259 loadDatabase();
00260 BOOST_CHECK(pDatabase->isRecoveryRequired());
00261 pDatabase->recover(*this);
00262 verifyData(15);
00263 }
00264
00265 void DatabaseTest::testForceTxns()
00266 {
00267 configMap.setStringParam(
00268 "forceTxns","true");
00269 configMap.setStringParam(
00270 "disableSnapshots","true");
00271 testCreateData();
00272 pDatabase->checkpointImpl();
00273 verifyData(5);
00274
00275
00276 PageId extraPageId = writeData(42);
00277
00278 pDatabase.reset();
00279 loadDatabase();
00280
00281
00282
00283 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00284 TestPageLock pageLock(segmentAccessor);
00285 pageLock.lockShared(extraPageId);
00286
00287 executeForceTxn();
00288 executeForceTxn();
00289
00290 pageLock.unlock();
00291
00292 pDatabase.reset();
00293 }
00294
00295 void DatabaseTest::executeForceTxn()
00296 {
00297 SharedLogicalTxn pTxn = pDatabase->getTxnLog()->newLogicalTxn(pCache);
00298 addTxnParticipant(pTxn);
00299 executeIncrementAction(10, ACTION_INCREMENT_FORCE);
00300 verifyData(15);
00301 pTxn->rollback();
00302 pTxn.reset();
00303
00304 snooze(3);
00305 pDatabase->recoverOnline();
00306 verifyData(5);
00307 }
00308
00309 void DatabaseTest::loadDatabase()
00310 {
00311 pDatabase = Database::newDatabase(
00312 pCache,
00313 configMap,
00314 DeviceMode::load,
00315 shared_from_this());
00316 }
00317
00318 LogicalTxnClassId DatabaseTest::getParticipantClassId() const
00319 {
00320 return LogicalTxnClassId(0xa470573b38dcaa0aLL);
00321 }
00322
00323 void DatabaseTest::describeParticipant(ByteOutputStream &)
00324 {
00325 }
00326
00327 void DatabaseTest::undoLogicalAction(
00328 LogicalActionType actionType,
00329 ByteInputStream &logStream)
00330 {
00331 int i;
00332 logStream.readValue(i);
00333 if (actionType == ACTION_INCREMENT_FORCE) {
00334 return;
00335 }
00336 assert(actionType == ACTION_INCREMENT);
00337 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00338 TestPageLock pageLock(segmentAccessor);
00339 pageLock.lockExclusive(persistentPageId);
00340 pageLock.getNodeForWrite().x -= i;
00341 }
00342
00343 void DatabaseTest::redoLogicalAction(
00344 LogicalActionType actionType,
00345 ByteInputStream &logStream)
00346 {
00347 int i;
00348 logStream.readValue(i);
00349 if (actionType == ACTION_INCREMENT_FORCE) {
00350 return;
00351 }
00352 assert(actionType == ACTION_INCREMENT);
00353 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00354 TestPageLock pageLock(segmentAccessor);
00355 pageLock.lockExclusive(persistentPageId);
00356 pageLock.getNodeForWrite().x += i;
00357 }
00358
00359 SharedLogicalTxnParticipant DatabaseTest::loadParticipant(
00360 LogicalTxnClassId classId,
00361 ByteInputStream &)
00362 {
00363 assert(classId == getParticipantClassId());
00364 return boost::dynamic_pointer_cast<LogicalTxnParticipant>(
00365 shared_from_this());
00366 }
00367
00368 void DatabaseTest::executeIncrementAction(int i)
00369 {
00370 executeIncrementAction(i, ACTION_INCREMENT);
00371 }
00372
00373 void DatabaseTest::executeIncrementAction(int i, LogicalActionType action)
00374 {
00375 ByteOutputStream &logStream =
00376 getLogicalTxn()->beginLogicalAction(*this,action);
00377 logStream.writeValue(i);
00378 getLogicalTxn()->endLogicalAction();
00379 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00380 TestPageLock pageLock(segmentAccessor);
00381 pageLock.lockExclusive(persistentPageId);
00382 pageLock.getNodeForWrite().x += i;
00383 }
00384
00385 void DatabaseTest::addTxnParticipant(SharedLogicalTxn pTxn)
00386 {
00387 pTxn->addParticipant(
00388 boost::dynamic_pointer_cast<LogicalTxnParticipant>(
00389 shared_from_this()));
00390 }
00391
00392 void DatabaseTest::executeIncrementTxn(int i)
00393 {
00394 SharedLogicalTxn pTxn = pDatabase->getTxnLog()->newLogicalTxn(pCache);
00395 addTxnParticipant(pTxn);
00396 executeIncrementAction(i);
00397 pTxn->commit();
00398 }
00399
00400 void DatabaseTest::executeCheckpointedTxn(
00401 int i,int j,bool commit,CheckpointType checkpointType)
00402 {
00403 SharedLogicalTxn pTxn = pDatabase->getTxnLog()->newLogicalTxn(pCache);
00404 addTxnParticipant(pTxn);
00405 executeIncrementAction(i);
00406 pDatabase->checkpointImpl(checkpointType);
00407 executeIncrementAction(j);
00408 if (commit) {
00409 pTxn->commit();
00410 } else {
00411 pTxn->rollback();
00412 }
00413 }
00414
00415 void DatabaseTest::verifyData(uint x)
00416 {
00417 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00418 TestPageLock pageLock(segmentAccessor);
00419 pageLock.lockShared(persistentPageId);
00420 BOOST_CHECK_EQUAL(pageLock.getNodeForRead().x,x);
00421 }
00422
00423 PageId DatabaseTest::writeData(uint x)
00424 {
00425 SegmentAccessor segmentAccessor(pDatabase->getDataSegment(),pCache);
00426 TestPageLock pageLock(segmentAccessor);
00427 PageId pageId = pageLock.allocatePage();
00428 pageLock.getNodeForWrite().x = x;
00429 pageLock.unlock();
00430 return pageId;
00431 }
00432
00433 FENNEL_UNIT_TEST_SUITE(DatabaseTest);
00434
00435