Fennel: /home/pub/open/dev/fennel/test/RandomAccessFileDeviceTest.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/common/FileSystem.h" 00026 #include "fennel/test/TestBase.h" 00027 #include "fennel/synch/SynchObj.h" 00028 #include "fennel/device/RandomAccessFileDevice.h" 00029 #include "fennel/device/RandomAccessRequest.h" 00030 #include "fennel/device/DeviceAccessScheduler.h" 00031 #include "fennel/device/DeviceAccessSchedulerParams.h" 00032 #include "fennel/cache/VMAllocator.h" 00033 #include 00034 #include 00035 #include <boost/test/test_tools.hpp> 00036 #include <boost/scoped_array.hpp> 00037 00038 using namespace fennel; 00039 00040 class RandomAccessFileDeviceTest : virtual public TestBase 00041 { 00042 static const uint ZERO_SIZE; 00043 static const uint HALF_SIZE; 00044 static const uint FULL_SIZE; 00045 00046 DeviceAccessSchedulerParams schedParams; 00047 SharedRandomAccessDevice pRandomAccessDevice; 00048 DeviceMode baseMode; 00049 00050 void openDevice(DeviceMode openMode,std::string devName) 00051 { 00052 if (openMode.create) { 00053 FileSystem::remove(devName.c_str()); 00054 } 00055 pRandomAccessDevice.reset( 00056 new RandomAccessFileDevice(devName,openMode)); 00057 } 00058 00059 void closeDevice() 00060 { 00061 pRandomAccessDevice.reset(); 00062 } 00063 00064 void testDeviceCreation() 00065 { 00066 const char *devName = "test.dat"; 00067 DeviceMode openMode = baseMode; 00068 openMode.create = 1; 00069 openDevice(openMode,devName); 00070 closeDevice(); 00071 if (openMode.temporary) { 00072 if (FileSystem::doesFileExist(devName)) { 00073 std::cerr << "temporary test.dat not deleted" << std::endl; 00074 } 00075 } else { 00076 openMode.create = 0; 00077 openDevice(openMode,devName); 00078 closeDevice(); 00079 } 00080 } 00081 00082 void testGrow() 00083 { 00084 const char *devName = "grow.dat"; 00085 DeviceMode openMode = baseMode; 00086 openMode.create = 1; 00087 openDevice(openMode,devName); 00088 BOOST_CHECK_EQUAL(ZERO_SIZE, pRandomAccessDevice->getSizeInBytes()); 00089 pRandomAccessDevice->setSizeInBytes(FULL_SIZE); 00090 BOOST_CHECK_EQUAL(FULL_SIZE, pRandomAccessDevice->getSizeInBytes()); 00091 closeDevice(); 00092 if (openMode.temporary) { 00093 return; 00094 } 00095 openMode.create = 0; 00096 openDevice(openMode,devName); 00097 BOOST_CHECK_EQUAL(FULL_SIZE, pRandomAccessDevice->getSizeInBytes()); 00098 closeDevice(); 00099 } 00100 00101 void testShrink() 00102 { 00103 const char devName = "shrink.dat"; 00104 DeviceMode openMode = baseMode; 00105 openMode.create = 1; 00106 openDevice(openMode,devName); 00107 BOOST_CHECK_EQUAL(ZERO_SIZE, pRandomAccessDevice->getSizeInBytes()); 00108 pRandomAccessDevice->setSizeInBytes(FULL_SIZE); 00109 BOOST_CHECK_EQUAL(FULL_SIZE, pRandomAccessDevice->getSizeInBytes()); 00110 closeDevice(); 00111 if (openMode.temporary) { 00112 return; 00113 } 00114 openMode.create = 0; 00115 openDevice(openMode,devName); 00116 BOOST_CHECK_EQUAL(FULL_SIZE, pRandomAccessDevice->getSizeInBytes()); 00117 pRandomAccessDevice->setSizeInBytes(HALF_SIZE); 00118 closeDevice(); 00119 openDevice(openMode,devName); 00120 BOOST_CHECK_EQUAL(HALF_SIZE, pRandomAccessDevice->getSizeInBytes()); 00121 closeDevice(); 00122 } 00123 00124 void testLargeFile() 00125 { 00126
00127 FileSize cbOffset = 0x40000000; 00128 cbOffset = 5; 00129 testAsyncIO(cbOffset); 00130 } 00131 00132 class Listener 00133 { 00134 StrictMutex mutex; 00135 LocalCondition cond; 00136 00137 public: 00138 int nTarget; 00139 int nSuccess; 00140 int nCompleted; 00141 00142 explicit Listener(int nTargetInit) 00143 { 00144 nTarget = nTargetInit; 00145 nSuccess = 0; 00146 nCompleted = 0; 00147 } 00148 virtual ~Listener() 00149 { 00150 } 00151 00152 StrictMutex &getMutex() 00153 { 00154 return mutex; 00155 } 00156 00157 void notifyTransferCompletion(bool b) 00158 { 00159 StrictMutexGuard mutexGuard(mutex); 00160 if (b) { 00161 nSuccess++; 00162 } 00163 nCompleted++; 00164 if (nCompleted == nTarget) { 00165 cond.notify_all(); 00166 } 00167 } 00168 00169 void waitForAll() 00170 { 00171 StrictMutexGuard mutexGuard(mutex); 00172 while (nCompleted < nTarget) { 00173 cond.wait(mutexGuard); 00174 } 00175 } 00176 }; 00177 00178 class Binding : public RandomAccessRequestBinding 00179 { 00180 Listener &listener; 00181 uint cb; 00182 PBuffer pBuffer; 00183 public: 00184 explicit Binding( 00185 Listener &listenerInit,uint cbInit,PBuffer pBufferInit) 00186 : listener(listenerInit),cb(cbInit),pBuffer(pBufferInit) 00187 { 00188 } 00189 00190 virtual ~Binding() 00191 { 00192 } 00193 00194 virtual PBuffer getBuffer() const 00195 { 00196 return pBuffer; 00197 } 00198 00199 virtual uint getBufferSize() const 00200 { 00201 return cb; 00202 } 00203 00204 virtual void notifyTransferCompletion(bool bSuccess) 00205 { 00206 listener.notifyTransferCompletion(bSuccess); 00207 } 00208 }; 00209 00210 void testAsyncIO() 00211 { 00212 testAsyncIO(0); 00213 } 00214 00215 void testRetryAsyncIO() 00216 { 00217 testAsyncIO(0, 5000); 00218 } 00219 00220 void testAsyncIO(FileSize cbOffset, int n = 5) 00221 { 00222 uint cbSector = HALF_SIZE; 00223 VMAllocator allocator(cbSector*n); 00224 void *pBuf = allocator.allocate(); 00225 void *pBuf2 = allocator.allocate(); 00226 BOOST_REQUIRE(pBuf != NULL); 00227 try { 00228 testAsyncIOImpl( 00229 n, cbSector, 00230 reinterpret_cast(pBuf), 00231 reinterpret_cast(pBuf2), 00232 cbOffset); 00233 } catch (...) { 00234 allocator.deallocate(pBuf); 00235 allocator.deallocate(pBuf2); 00236 throw; 00237 } 00238 allocator.deallocate(pBuf); 00239 allocator.deallocate(pBuf2); 00240 } 00241 00242 void testAsyncIOImpl( 00243 int n, uint cbSector, 00244 PBuffer pBuf, PBuffer pBuf2, FileSize cbOffset = 0) 00245 { 00246 DeviceAccessScheduler pScheduler = 00247 DeviceAccessScheduler::newScheduler(schedParams); 00248 00249 const char devName = "async.dat"; 00250 DeviceMode openMode = baseMode; 00251 openMode.create = 1; 00252 openDevice(openMode,devName); 00253 FileSize cbFile = cbOffset; 00254 cbFile += ncbSector; 00255 pRandomAccessDevice->setSizeInBytes(cbFile); 00256 00257
00258 if (!openMode.temporary) { 00259 closeDevice(); 00260 openMode.create = 0; 00261 openDevice(openMode,devName); 00262 FileSize cbFileActual = pRandomAccessDevice->getSizeInBytes(); 00263 BOOST_CHECK_EQUAL(cbFile, cbFileActual); 00264 } 00265 00266 pScheduler->registerDevice(pRandomAccessDevice); 00267 std::string s = "Four score and seven years ago."; 00268 char const writeBuf = s.c_str(); 00269 uint cb = s.size(); 00270 00271 Listener writeListener(n); 00272 RandomAccessRequest writeRequest; 00273 writeRequest.pDevice = pRandomAccessDevice.get(); 00274 writeRequest.cbOffset = cbOffset; 00275 writeRequest.cbTransfer=ncbSector; 00276 writeRequest.type = RandomAccessRequest::WRITE; 00277 memcpy(pBuf, writeBuf, cb); 00278 for (int i = 0; i < n; i++) { 00279 Binding *pBinding = new Binding( 00280 writeListener,cbSector,PBuffer(pBuf)); 00281 writeRequest.bindingList.push_back(*pBinding); 00282 } 00283 00284
00285
00286
00287 StrictMutexGuard mutexGuard(writeListener.getMutex()); 00288 pScheduler->schedule(writeRequest); 00289 mutexGuard.unlock(); 00290 00291 writeListener.waitForAll(); 00292 BOOST_CHECK_EQUAL(n, writeListener.nSuccess); 00293 pRandomAccessDevice->flush(); 00294 00295 if (!openMode.temporary) { 00296 pScheduler->unregisterDevice(pRandomAccessDevice); 00297 closeDevice(); 00298 openMode.create = 0; 00299 openDevice(openMode,devName); 00300 pScheduler->registerDevice(pRandomAccessDevice); 00301 } 00302 00303 Listener readListener(n + 1); 00304 RandomAccessRequest readRequest; 00305 readRequest.pDevice = pRandomAccessDevice.get(); 00306 readRequest.cbOffset = cbOffset; 00307 readRequest.cbTransfer = n
cbSector; 00308 readRequest.type = RandomAccessRequest::READ; 00309 for (int i = 0; i < n; i++) { 00310 Binding *pBinding = new Binding( 00311 readListener,cbSector, 00312 pBuf + i*cbSector); 00313 readRequest.bindingList.push_back(*pBinding); 00314 } 00315 00316
00317
00318
00319 RandomAccessRequest readRequest2; 00320 readRequest2.pDevice = pRandomAccessDevice.get(); 00321 readRequest2.cbOffset = cbOffset; 00322 readRequest2.cbTransfer = cbSector; 00323 readRequest2.type = RandomAccessRequest::READ; 00324 Binding *pBinding = new Binding( 00325 readListener, cbSector, pBuf2); 00326 readRequest2.bindingList.push_back(*pBinding); 00327 00328 pScheduler->schedule(readRequest); 00329 pScheduler->schedule(readRequest2); 00330 readListener.waitForAll(); 00331 BOOST_CHECK_EQUAL(n + 1, readListener.nSuccess); 00332 for (int i = 0; i < n; i++) { 00333 std::string s2(reinterpret_cast<char *>(pBuf + i
cbSector),cb); 00334 BOOST_CHECK_EQUAL(s,s2); 00335 } 00336 std::string s3(reinterpret_cast<char *>(pBuf2),cb); 00337 BOOST_CHECK_EQUAL(s,s3); 00338 00339 pScheduler->unregisterDevice(pRandomAccessDevice); 00340 closeDevice(); 00341 00342 pScheduler->stop(); 00343 delete pScheduler; 00344 } 00345 00346 public: 00347 explicit RandomAccessFileDeviceTest() 00348 { 00349 schedParams.readConfig(configMap); 00350 FENNEL_UNIT_TEST_CASE(RandomAccessFileDeviceTest,testPermanentNoDirect); 00351 FENNEL_UNIT_TEST_CASE(RandomAccessFileDeviceTest,testTemporary); 00352 FENNEL_UNIT_TEST_CASE(RandomAccessFileDeviceTest,testPermanentDirect); 00353 FENNEL_UNIT_TEST_CASE(RandomAccessFileDeviceTest,testRetryAsyncIO); 00354 00355
00356
00357
00358 FENNEL_EXTRA_UNIT_TEST_CASE( 00359 RandomAccessFileDeviceTest,testLargeFile); 00360 } 00361 00362 void testPermanentNoDirect() 00363 { 00364 baseMode = DeviceMode::load; 00365 runModeTests(); 00366 } 00367 00368 void testTemporary() 00369 { 00370 baseMode = DeviceMode::load; 00371 baseMode.temporary = true; 00372 runModeTests(); 00373 } 00374 00375 void testPermanentDirect() 00376 { 00377 baseMode = DeviceMode::load; 00378 baseMode.direct = true; 00379 runModeTests(); 00380 } 00381 00382 void runModeTests() 00383 { 00384 testDeviceCreation(); 00385 testGrow(); 00386 testShrink(); 00387 testAsyncIO(); 00388 } 00389 00390 virtual void testCaseTearDown() 00391 { 00392 closeDevice(); 00393 } 00394 }; 00395 00396 00397 00398 const uint RandomAccessFileDeviceTest::ZERO_SIZE = 0; 00399 const uint RandomAccessFileDeviceTest::HALF_SIZE = 4096; 00400 const uint RandomAccessFileDeviceTest::FULL_SIZE = 2
HALF_SIZE; 00401 00402 FENNEL_UNIT_TEST_SUITE(RandomAccessFileDeviceTest); 00403 00404