CacheTest.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/test/CacheTest.cpp#14 $
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/test/CacheTestBase.h"
00026 #include "fennel/test/PagingTestBase.h"
00027 #include "fennel/cache/Cache.h"
00028 #include "fennel/cache/QuotaCacheAccessor.h"
00029 #include "fennel/common/CompoundId.h"
00030 
00031 #include <boost/test/test_tools.hpp>
00032 
00033 #ifdef HAVE_MMAP
00034 #include <sys/resource.h>
00035 #endif
00036 
00037 using namespace fennel;
00038 
00039 #define SMALL_ADDR_SPACE (192 * 1024 * 1024) // 192 MB
00040 
00051 class CacheTest : virtual public PagingTestBase
00052 {
00053 public:
00057     BlockId makeBlockId(uint i)
00058     {
00059         assert(i < nDiskPages);
00060         BlockId blockId(0);
00061         CompoundId::setDeviceId(blockId,dataDeviceId);
00062         CompoundId::setBlockNum(blockId,i);
00063         return blockId;
00064     }
00065 
00066     virtual CachePage *lockPage(OpType opType,uint iPage)
00067     {
00068         BlockId blockId = makeBlockId(iPage);
00069         return getCache().lockPage(
00070             blockId,getLockMode(opType),opType != OP_ALLOCATE);
00071     }
00072 
00073     virtual void unlockPage(CachePage &page,LockMode lockMode)
00074     {
00075         getCache().unlockPage(page,lockMode);
00076     }
00077 
00078     virtual void prefetchPage(uint iPage)
00079     {
00080         BlockId blockId = makeBlockId(iPage);
00081         getCache().prefetchPage(blockId);
00082     }
00083 
00084     virtual void prefetchBatch(uint iPage,uint nPagesPerBatch)
00085     {
00086         BlockId blockId = makeBlockId(iPage);
00087         getCache().prefetchBatch(blockId,nPagesPerBatch);
00088     }
00089 
00090     explicit CacheTest()
00091     {
00092         // disable irrelevant threads
00093         threadCounts[OP_ALLOCATE] = 0;
00094         threadCounts[OP_DEALLOCATE] = 0;
00095 
00096         cbPageUsable = cbPageFull;
00097 
00098         FENNEL_UNIT_TEST_CASE(CacheTest,testSingleThread);
00099         FENNEL_UNIT_TEST_CASE(CacheTest,testQuotaCacheAccessor);
00100         FENNEL_UNIT_TEST_CASE(PagingTestBase,testMultipleThreads);
00101 
00102 #ifdef RLIMIT_AS
00103         FENNEL_EXTRA_UNIT_TEST_CASE(CacheTest,testLargeCacheInit);
00104         FENNEL_EXTRA_UNIT_TEST_CASE(CacheTest,testLargeCacheRequest);
00105 #endif
00106     }
00107 
00108     void testSingleThread()
00109     {
00110         openStorage(DeviceMode::createNew);
00111         testAllocateAll();
00112         testSequentialRead();
00113         testRandomRead();
00114         testScratch();
00115         testSequentialWrite();
00116         testRandomWrite();
00117         closeStorage();
00118         openStorage(DeviceMode::load);
00119         testRandomRead();
00120         testSequentialRead();
00121         closeStorage();
00122     }
00123 
00124     void testQuotaCacheAccessor()
00125     {
00126         openStorage(DeviceMode::createNew);
00127         QuotaCacheAccessor *pQuota = new QuotaCacheAccessor(
00128             SharedQuotaCacheAccessor(),pCache,5);
00129         SharedCacheAccessor pSharedQuota(pQuota);
00130         BOOST_CHECK_EQUAL(pQuota->getMaxLockedPages(),5U);
00131         BOOST_CHECK_EQUAL(pQuota->getLockedPageCount(),0U);
00132         CachePage *pPage = pQuota->lockPage(makeBlockId(0),LOCKMODE_S,0);
00133         BOOST_CHECK_EQUAL(pQuota->getLockedPageCount(),1U);
00134         pQuota->unlockPage(*pPage,LOCKMODE_S);
00135         BOOST_CHECK_EQUAL(pQuota->getLockedPageCount(),0U);
00136         pSharedQuota.reset();
00137         closeStorage();
00138     }
00139 
00140 #ifdef RLIMIT_AS
00141     // Sets max address space to minLimit if lower than the current limit.
00142     // Returns the limit in effect upon return.
00143     rlim_t setAddressSpaceLimit(rlim_t minLimit, struct rlimit &oldLimits)
00144     {
00145         int rv = getrlimit(RLIMIT_AS, &oldLimits);
00146         BOOST_REQUIRE(rv == 0);
00147 
00148         // Modify them, if necessary
00149         if (oldLimits.rlim_cur > minLimit) {
00150             // Lower current "soft" limit
00151             struct rlimit new_limits;
00152             new_limits.rlim_cur = minLimit;
00153             new_limits.rlim_max = oldLimits.rlim_max;
00154 
00155             rv = setrlimit(RLIMIT_AS, &new_limits);
00156             BOOST_REQUIRE(rv == 0);
00157 
00158             return minLimit;
00159         }
00160 
00161         return oldLimits.rlim_cur;
00162     }
00163 
00164     // Resets limit to values returned by reference in setAddressSpaceLimit
00165     void restoreAddressSpaceLimit(const struct rlimit &limits)
00166     {
00167         // restore addres space limits
00168         int rv = setrlimit(RLIMIT_AS, &limits);
00169         BOOST_REQUIRE(rv == 0);
00170     }
00171 
00172     uint computeMaxPagesUpperBound(uint addressSpaceSize, uint pageSize)
00173     {
00174         int guardPages = 0;
00175 #ifndef NDEBUG
00176         // In debug mode, guard pages flank each real page.
00177         guardPages = 2;
00178 #endif
00179         int osPageSize = getpagesize();
00180 
00181         return addressSpaceSize / (pageSize + (guardPages * osPageSize) + 4);
00182     }
00183 
00184     void testLargeCacheInit()
00185     {
00186         struct rlimit savedLimits;
00187 
00188         rlim_t addrSpaceSize = setAddressSpaceLimit(
00189             SMALL_ADDR_SPACE, savedLimits);
00190 
00191         CacheParams params;
00192 
00193         // Ask for so many max pages, that CacheImpl cannot keep track of them
00194         // all (e.g., vector of page pointers is larger than address space
00195         // limit)
00196         params.nMemPagesMax = addrSpaceSize / sizeof(void *) + 100;
00197         params.nMemPagesInit = 10;
00198 
00199         SharedCache pCache;
00200 
00201         BOOST_CHECK_NO_THROW(pCache = Cache::newCache(params));
00202         BOOST_CHECK_EQUAL(
00203             CacheParams::defaultMemPagesMax,
00204             pCache->getMaxAllocatedPageCount());
00205 
00206         // Note: use of CacheParams::defaultMemPagesMax is correct here.  When
00207         // we reset the max pages value due to an exception we automatically
00208         // reset the init value to the default (MAXU), which causes the
00209         // allocated page count to be equal to the MAX.
00210         BOOST_CHECK_EQUAL(
00211             CacheParams::defaultMemPagesMax,
00212             pCache->getAllocatedPageCount());
00213 
00214         pCache.reset();
00215 
00216         // Set max pages such that allocating that many pages would exceed the
00217         // process address space.  Try to initialize with that many pages.
00218 
00219         // REVIEW: SWZ: 10/11/2007: Using the default page size (4K), we're
00220         // unable to munmap any pages once we realize we've run out.  Seems
00221         // like an OS bug -- larger pages works fine.  I attempted to use as
00222         // few 4K pages as possible (determined empirically -- the address
00223         // space includes libraries that may vary across machines or builds)
00224         // and it was still unable to munmap any pages once it ran out.
00225         params.cbPage = 32 * 1024;
00226 
00227         params.nMemPagesMax =
00228             computeMaxPagesUpperBound(addrSpaceSize, params.cbPage);
00229         params.nMemPagesInit = params.nMemPagesMax;
00230 
00231         BOOST_CHECK_NO_THROW(pCache = Cache::newCache(params));
00232         BOOST_CHECK_EQUAL(
00233             CacheParams::defaultMemPagesMax,
00234             pCache->getMaxAllocatedPageCount());
00235 
00236         // See note above; same logic.
00237         BOOST_CHECK_EQUAL(
00238             CacheParams::defaultMemPagesMax,
00239             pCache->getAllocatedPageCount());
00240 
00241         pCache.reset();
00242 
00243         restoreAddressSpaceLimit(savedLimits);
00244     }
00245 
00246     void testLargeCacheRequest()
00247     {
00248         struct rlimit savedLimits;
00249 
00250         rlim_t addrSpaceSize =
00251             setAddressSpaceLimit(SMALL_ADDR_SPACE, savedLimits);
00252 
00253         CacheParams params;
00254 
00255         // REVIEW: SWZ: 10/11/2007: Same page size weirdness as in
00256         // testLargeCacheInit.
00257         params.cbPage = 32 * 1024;
00258 
00259         params.nMemPagesMax =
00260             computeMaxPagesUpperBound(addrSpaceSize, params.cbPage);
00261         params.nMemPagesInit =
00262             (params.nMemPagesMax / 2) < 1000
00263             ? (params.nMemPagesMax / 2)
00264             : 1000;
00265 
00266         BOOST_CHECK_NO_THROW(pCache = Cache::newCache(params));
00267         BOOST_CHECK_EQUAL(
00268             params.nMemPagesMax,
00269             pCache->getMaxAllocatedPageCount());
00270         BOOST_CHECK_EQUAL(
00271             params.nMemPagesInit,
00272             pCache->getAllocatedPageCount());
00273 
00274         BOOST_CHECK_THROW(
00275             pCache->setAllocatedPageCount(params.nMemPagesMax),
00276             std::exception);
00277         BOOST_CHECK_EQUAL(
00278             params.nMemPagesMax,
00279             pCache->getMaxAllocatedPageCount());
00280         BOOST_CHECK_EQUAL(
00281             params.nMemPagesInit,
00282             pCache->getAllocatedPageCount());
00283 
00284         pCache.reset();
00285 
00286         restoreAddressSpaceLimit(savedLimits);
00287     }
00288 #endif // RLIMIT_AS
00289 };
00290 
00291 FENNEL_UNIT_TEST_SUITE(CacheTest);
00292 
00293 // End CacheTest.cpp

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