SnapshotSegmentTest.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/test/SnapshotSegmentTest.cpp#13 $
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/SnapshotSegmentTestBase.h"
00026 #include "fennel/segment/VersionedRandomAllocationSegment.h"
00027 #include "fennel/cache/CacheStats.h"
00028 
00029 #include <boost/test/test_tools.hpp>
00030 
00031 using namespace fennel;
00032 
00033 class SnapshotSegmentTest : virtual public SnapshotSegmentTestBase
00034 {
00035 public:
00036     explicit SnapshotSegmentTest()
00037     {
00038         FENNEL_UNIT_TEST_CASE(SegmentTestBase, testSingleThread);
00039         FENNEL_UNIT_TEST_CASE(PagingTestBase, testMultipleThreads);
00040         FENNEL_UNIT_TEST_CASE(SnapshotSegmentTest, testSnapshotReads);
00041         FENNEL_UNIT_TEST_CASE(SnapshotSegmentTest, testRollback);
00042         FENNEL_UNIT_TEST_CASE(SnapshotSegmentTest, testUncommittedReads);
00043         FENNEL_UNIT_TEST_CASE(SnapshotSegmentTest, testDeallocateOld);
00044     }
00045 
00046     void testSnapshotReads()
00047     {
00048         // Create and initialize a VersionedRandomAllocationSegment using
00049         // a snapshot with TxnId(0)
00050         currCsn = TxnId(0);
00051         openStorage(DeviceMode::createNew);
00052         testAllocateAll();
00053         closeStorage();
00054 
00055         // Create a snapshot at TxnId(5) where every 5 pages are updated
00056         updatedCsns.push_back(TxnId(5));
00057         currCsn = TxnId(5);
00058         openStorage(DeviceMode::load);
00059         testSkipWrite(5);
00060         closeStorage();
00061 
00062         // Create a snapshot at TxnId(7) where every 7 pages are updated
00063         updatedCsns.push_back(TxnId(7));
00064         currCsn = TxnId(7);
00065         openStorage(DeviceMode::load);
00066         testSkipWrite(7);
00067         closeStorage();
00068 
00069         // Read all pages as of txnIds 0-9
00070         for (uint i = 0; i < 10; i++) {
00071             currCsn = TxnId(i);
00072             openStorage(DeviceMode::load);
00073             testSequentialRead();
00074             closeStorage();
00075         }
00076     }
00077 
00078     void testRollback()
00079     {
00080         // Create and initialize a VersionedRandomAllocationSegment using
00081         // a snapshot with TxnId(0)
00082         currCsn = TxnId(0);
00083         openStorage(DeviceMode::createNew);
00084         testAllocateAll();
00085         closeStorage();
00086 
00087         // Create a snapshot at TxnId(1) where every 5 pages are updated,
00088         // but rollback the changes
00089         currCsn = TxnId(1);
00090         openStorage(DeviceMode::load);
00091         testSkipWrite(5);
00092         // Make sure new pages have been allocated before we roll them back
00093         assert(
00094             pVersionedRandomSegment->getAllocatedSizeInPages() ==
00095             nDiskPages + nDiskPages / 5 + ((nDiskPages % 5) ? 1 : 0));
00096         commit = false;
00097         closeStorage();
00098         commit = true;
00099 
00100         // Read all pages as of TxnId(2).  Changes from TxnId(1) should not
00101         // be seen.
00102         currCsn = TxnId(2);
00103         openStorage(DeviceMode::load);
00104         testSequentialRead();
00105         closeStorage();
00106     }
00107 
00108     void testUncommittedReads()
00109     {
00110         // Create and initialize a VersionedRandomAllocationSegment using
00111         // a snapshot with TxnId(0)
00112         currCsn = TxnId(0);
00113         openStorage(DeviceMode::createNew);
00114         testAllocateAll();
00115         closeStorage();
00116 
00117         // Create a snapshot at TxnId(5) where every 5 pages are updated,
00118         // but don't commit the changes yet.
00119         currCsn = TxnId(5);
00120         openStorage(DeviceMode::load);
00121         testSkipWrite(5);
00122 
00123         // Setup a new snapshot segment since we still want to keep around
00124         // the uncommitted TxnId(5)
00125         closeLinearSegment();
00126         pSnapshotRandomSegment2 =
00127             pSegmentFactory->newSnapshotRandomAllocationSegment(
00128                 pVersionedRandomSegment,
00129                 pVersionedRandomSegment,
00130                 TxnId(6));
00131         setForceCacheUnmap(pSnapshotRandomSegment2);
00132         SharedSegment pLinearViewSegment =
00133             pSegmentFactory->newLinearViewSegment(
00134                 pSnapshotRandomSegment2,
00135                 firstPageId);
00136         pLinearSegment = pLinearViewSegment;
00137 
00138         // Read all pages as of TxnId(6).  Changes from TxnId(5) should not
00139         // be seen since it's not committed yet.
00140         testSequentialRead();
00141         pLinearViewSegment.reset();
00142 
00143         // Setup a snapshot segment that reads pages as of TxnId(5), but
00144         // ignores uncommitted updates.
00145         pSnapshotRandomSegment2.reset();
00146         closeLinearSegment();
00147         pSnapshotRandomSegment2 =
00148             pSegmentFactory->newSnapshotRandomAllocationSegment(
00149                 pVersionedRandomSegment,
00150                 pVersionedRandomSegment,
00151                 TxnId(5),
00152                 true);
00153         setForceCacheUnmap(pSnapshotRandomSegment2);
00154         pLinearViewSegment =
00155             pSegmentFactory->newLinearViewSegment(
00156                 pSnapshotRandomSegment2,
00157                 firstPageId);
00158         pLinearSegment = pLinearViewSegment;
00159         testSequentialRead();
00160         pLinearViewSegment.reset();
00161 
00162         // Commit TxnId(5)
00163         closeStorage();
00164 
00165         // Now we should see TxnId(5)
00166         updatedCsns.push_back(TxnId(5));
00167         currCsn = TxnId(6);
00168         openStorage(DeviceMode::load);
00169         testSequentialRead();
00170         closeStorage();
00171     }
00172 
00173     void testDeallocateOld()
00174     {
00175         // Create and initialize a VersionedRandomAllocationSegment using
00176         // a snapshot with TxnId(0)
00177         currCsn = TxnId(0);
00178         openStorage(DeviceMode::createNew);
00179         testAllocateAll();
00180         closeStorage();
00181 
00182         // Create a snapshot at TxnId(3) where every 3 pages are updated
00183         updatedCsns.push_back(TxnId(3));
00184         currCsn = TxnId(3);
00185         openStorage(DeviceMode::load);
00186         testSkipWrite(3);
00187         closeStorage();
00188 
00189         // Create a snapshot at TxnId(5) where every 5 pages are updated
00190         updatedCsns.push_back(TxnId(5));
00191         currCsn = TxnId(5);
00192         openStorage(DeviceMode::load);
00193         testSkipWrite(5);
00194         closeStorage();
00195 
00196         // Create a snapshot at TxnId(7) where every 7 pages are updated
00197         updatedCsns.push_back(TxnId(7));
00198         currCsn = TxnId(7);
00199         openStorage(DeviceMode::load);
00200         testSkipWrite(7);
00201         closeStorage();
00202 
00203         uint totalPages =
00204             nDiskPages +
00205             nDiskPages / 3 + ((nDiskPages % 3) ? 1 : 0) +
00206             nDiskPages / 5 + ((nDiskPages % 5) ? 1 : 0) +
00207             nDiskPages / 7 + ((nDiskPages % 7) ? 1 : 0);
00208 
00209         // Deallocate pages -- set the oldestActiveTxnId at TxnId(3).  No
00210         // pages should be deallocated.
00211         deallocateOldPages(TxnId(3), totalPages, totalPages, 3, 8);
00212 
00213         // Deallocate pages -- set the oldestActiveTxnId at TxnId(4).  No
00214         // pages should be deallocated.
00215         deallocateOldPages(TxnId(4), totalPages, totalPages, 4, 8);
00216 
00217         // Deallocate pages -- set the oldestActiveTxnId at TxnId(6).  Only
00218         // pages with both TxnId(3) and TxnId(5) in their page chain should
00219         // be deallocated, with only the TxnId(3) pages being deallocated.
00220         uint nPages =
00221             totalPages - (nDiskPages/(3*5) + ((nDiskPages % (3*5)) ? 1 : 0));
00222         deallocateOldPages(TxnId(6), totalPages, nPages, 6, 8);
00223 
00224         // Deallocate pages -- set the oldestActiveTxnId at TxnId(8).  Pages
00225         // with only 2 old pages in the chain can be deallocated, with only
00226         // the older of the two being deallocated.
00227         totalPages = nPages;
00228         nPages =
00229             totalPages -
00230                 (nDiskPages/(5*7) + ((nDiskPages % (5*7)) ? 1 : 0)) -
00231                 (nDiskPages/(3*7) + ((nDiskPages % (3*7)) ? 1 : 0)) +
00232                 (nDiskPages/(3*5*7) + ((nDiskPages % (3*5*7)) ? 1 : 0));
00233         deallocateOldPages(TxnId(8), totalPages, nPages, 8, 8);
00234 
00235         // Deallocate the first 100 pages.  They won't actually be freed but
00236         // will be marked as deallocation-deferred.
00237         currCsn = TxnId(9);
00238         openStorage(DeviceMode::load);
00239 
00240         // Read all pages into cache to test discard behavior.
00241         testSequentialRead();
00242 
00243         // Save cache stats before deallocation.
00244         CacheStats statsBefore;
00245         pCache->collectStats(statsBefore);
00246 
00247         for (int i = opaqueToInt(firstPageId);
00248             i < 100 + opaqueToInt(firstPageId); i++)
00249         {
00250             pSnapshotRandomSegment->deallocatePageRange(PageId(i), PageId(i));
00251         }
00252 
00253         // Get cache stats after deallocation and compare.
00254         CacheStats statsAfter;
00255         pCache->collectStats(statsAfter);
00256 
00257         // Count of unused pages should not go up since deallocation is
00258         // deferred.
00259         BOOST_CHECK(statsAfter.nMemPagesUnused <= statsBefore.nMemPagesUnused);
00260 
00261         closeStorage();
00262 
00263         // Deallocate old pages, but set the oldestActiveTxnId to TxnId(0) so
00264         // no pages should actually be freed
00265         deallocateOldPages(TxnId(0), nPages, nPages, 8, 8);
00266 
00267         // Set the oldestActiveTnxId to TxnId(10) so all deallocation-deferred
00268         // pages will be freed.  When computing the number of freed pages,
00269         // take into account old pages that have already been deallocated
00270         // above.
00271         int nPagesFreed =
00272             100 + 100/3 + 100/5 + 100/7 - 100/(3*5) - 100/(3*7) - 100/(5*7)
00273             - 100/(3*5*7);
00274         deallocateOldPages(TxnId(10), nPages, nPages - nPagesFreed, 1, 0);
00275     }
00276 
00277     void deallocateOldPages(
00278         TxnId oldestActiveTxnId,
00279         uint numPagesBefore,
00280         uint numPagesAfter,
00281         uint readStart,
00282         uint readEnd)
00283     {
00284         currCsn = TxnId(10);
00285         openStorage(DeviceMode::load);
00286         VersionedRandomAllocationSegment *pVRSegment =
00287             SegmentFactory::dynamicCast<VersionedRandomAllocationSegment *>(
00288                 pVersionedRandomSegment);
00289         uint nPages = pVRSegment->getAllocatedSizeInPages();
00290         assert(nPages == numPagesBefore);
00291         uint iSegAlloc = 0;
00292         ExtentNum extentNum = 0;
00293         uint numPages = 100;
00294         PageSet oldPageSet;
00295         bool morePages = true;
00296         do {
00297             morePages =
00298                 pVRSegment->getOldPageIds(
00299                     iSegAlloc,
00300                     extentNum,
00301                     oldestActiveTxnId,
00302                     numPages,
00303                     oldPageSet);
00304             pVRSegment->deallocateOldPages(oldPageSet, oldestActiveTxnId);
00305             oldPageSet.clear();
00306         } while (morePages);
00307         nPages = pVRSegment->getAllocatedSizeInPages();
00308         assert(nPages == numPagesAfter);
00309         closeStorage();
00310 
00311         // Read all pages for the specified TxnId range
00312         for (uint i = readStart; i <= readEnd; i++) {
00313             currCsn = TxnId(i);
00314             openStorage(DeviceMode::load);
00315             testSequentialRead();
00316             closeStorage();
00317         }
00318     }
00319 };
00320 
00321 FENNEL_UNIT_TEST_SUITE(SnapshotSegmentTest);
00322 
00323 // End SnapshotSegmentTest.cpp

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