Fennel: /home/pub/open/dev/fennel/test/DatabaseTest.cpp Source File (original) (raw)

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 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( 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( 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