Fennel: /home/pub/open/dev/fennel/segment/RandomAllocationSegmentBase.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/segment/RandomAllocationSegmentBaseImpl.h" 00026 00027 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/segment/RandomAllocationSegmentBase.cpp#12 $"); 00028 00029 00030 00031 00032 00033 00034 00035 00036 00037 00038 00039 00040 00041 RandomAllocationSegmentBase::RandomAllocationSegmentBase( 00042 SharedSegment delegateSegment) 00043 : DelegatingSegment(delegateSegment) 00044 { 00045 permAssert(DelegatingSegment::getAllocationOrder() == LINEAR_ALLOCATION); 00046 00047
00048 00049 nExtentsPerSegAlloc = 00050 (getUsablePageSize() - sizeof(SegmentAllocationNode)) 00051 / sizeof(SegmentAllocationNode::ExtentEntry); 00052 00053 nPagesOccupiedHighWater = 0; 00054 nPagesAllocated = 0; 00055 netDeallocations = 0; 00056 } 00057 00058 RandomAllocationSegmentBase::~RandomAllocationSegmentBase() 00059 { 00060 } 00061 00062 void RandomAllocationSegmentBase::initForUse() 00063 { 00064 countAllocatedPages(); 00065 } 00066 00067 void RandomAllocationSegmentBase::format() 00068 { 00069
00070 uint nSegAllocPages = inferSegAllocCount(); 00071 00072
00073 ExtentNum nExtents = (nSegAllocPages-1)nExtentsPerSegAlloc; 00074 00075
00076 BlockNum nRemainderPages = DelegatingSegment::getAllocatedSizeInPages(); 00077 nRemainderPages -= (nExtents
nPagesPerExtent+nSegAllocPages); 00078 00079 if (nRemainderPages) { 00080
00081
00082 nExtents += nRemainderPages / nPagesPerExtent; 00083 } else { 00084
00085 nExtents += nExtentsPerSegAlloc; 00086 } 00087 00088
00089
00090 if (!nExtents) { 00091 nSegAllocPages = 1; 00092 nExtents = 1; 00093 } 00094 00095
00096 bool bigEnough = DelegatingSegment::ensureAllocatedSize( 00097 nExtents*nPagesPerExtent + nSegAllocPages); 00098 permAssert(bigEnough); 00099 00100
00101 00102 ExtentNum extentNum = 0; 00103 SegmentAccessor selfAccessor(getTracingSegment(), pCache); 00104 SegAllocLock segAllocLock(selfAccessor); 00105 for (uint iSegAlloc = 0; iSegAlloc < nSegAllocPages; iSegAlloc++) { 00106 PageId segAllocPageId = getSegAllocPageId(iSegAlloc); 00107 segAllocLock.lockExclusive(segAllocPageId); 00108 00109
00110
00111
00112 segAllocLock.setMagicNumber(); 00113 SegmentAllocationNode &segAllocNode = segAllocLock.getNodeForWrite(); 00114 00115 uint iNextSegAlloc = iSegAlloc + 1; 00116 if (iNextSegAlloc < nSegAllocPages) { 00117
00118 segAllocNode.nextSegAllocPageId = getSegAllocPageId(iNextSegAlloc); 00119 } else { 00120
00121 segAllocNode.nextSegAllocPageId = NULL_PAGE_ID; 00122 } 00123 00124
00125 segAllocNode.nPagesPerExtent = nPagesPerExtent; 00126 segAllocNode.nExtents = std::min(nExtents,nExtentsPerSegAlloc); 00127 nExtents -= segAllocNode.nExtents; 00128 00129
00130 formatPageExtents(segAllocNode, extentNum); 00131 } 00132 00133 permAssert(!nExtents); 00134 } 00135 00136 void RandomAllocationSegmentBase::markPageEntryUnused( 00137 PageEntry &pageEntry) 00138 { 00139 pageEntry.ownerId = UNALLOCATED_PAGE_OWNER_ID; 00140 pageEntry.successorId = NULL_PAGE_ID; 00141 } 00142 00143 uint RandomAllocationSegmentBase::inferSegAllocCount() 00144 { 00145 BlockNum nPages = DelegatingSegment::getAllocatedSizeInPages(); 00146
00147 return nPages / nPagesPerSegAlloc + 00148 (nPages % nPagesPerSegAlloc ? 1 : 0); 00149 } 00150 00151 PageId RandomAllocationSegmentBase::allocatePageIdFromSegment( 00152 PageOwnerId ownerId, 00153 SharedSegment allocNodeSegment) 00154 { 00155 ExtentNum extentNum = 0; 00156 SegmentAccessor segAccessor(allocNodeSegment, pCache); 00157 SegAllocLock segAllocLock(segAccessor); 00158 00159
00160 PageId origSegAllocPageId = getFirstSegAllocPageId(); 00161 PageId segAllocPageId = getSegAllocPageIdForWrite(origSegAllocPageId); 00162 for (uint iSegAlloc = 0; ; ++iSegAlloc) { 00163
00164
00165
00166 segAllocLock.lockExclusive(segAllocPageId); 00167 SegmentAllocationNode const &readOnlySegAllocNode = 00168 segAllocLock.getNodeForRead(); 00169 00170
00171 for (uint i = 0; i < readOnlySegAllocNode.nExtents; ++i, ++extentNum) { 00172 SegmentAllocationNode::ExtentEntry const &readOnlyExtentEntry = 00173 readOnlySegAllocNode.getExtentEntry(i); 00174 if (readOnlyExtentEntry.nUnallocatedPages) { 00175
00176 SegmentAllocationNode &writableSegAllocNode = 00177 segAllocLock.getNodeForWrite(); 00178 SegmentAllocationNode::ExtentEntry &writableExtentEntry = 00179 writableSegAllocNode.getExtentEntry(i); 00180 writableExtentEntry.nUnallocatedPages--; 00181
00182
00183
00184
00185
00186 segAllocLock.unlock(); 00187 incrementPageCounters(); 00188 return allocateFromExtent(extentNum,ownerId); 00189 } 00190 } 00191 00192 if (readOnlySegAllocNode.nextSegAllocPageId != NULL_PAGE_ID) { 00193
00194
00195 undoSegAllocPageWrite(origSegAllocPageId); 00196 00197
00198 origSegAllocPageId = readOnlySegAllocNode.nextSegAllocPageId; 00199 segAllocPageId = getSegAllocPageIdForWrite(origSegAllocPageId); 00200 continue; 00201 } 00202 00203
00204
00205
00206 00207 if (readOnlySegAllocNode.nExtents < nExtentsPerSegAlloc) { 00208
00209
00210
00211 try { 00212 if (DelegatingSegment::ensureAllocatedSize( 00213 makePageNum(extentNum,nPagesPerExtent))) 00214 { 00215
00216 undoSegAllocPageWrite(origSegAllocPageId); 00217 return NULL_PAGE_ID; 00218 } 00219 } catch (...) { 00220 undoSegAllocPageWrite(origSegAllocPageId); 00221 throw; 00222 } 00223 00224
00225 SegmentAllocationNode &writableSegAllocNode = 00226 segAllocLock.getNodeForWrite(); 00227 writableSegAllocNode.nExtents++; 00228 SegmentAllocationNode::ExtentEntry &writableExtentEntry = 00229 writableSegAllocNode.getExtentEntry( 00230 writableSegAllocNode.nExtents - 1); 00231 00232
00233
00234 writableExtentEntry.nUnallocatedPages = nPagesPerExtent - 2; 00235 00236 incrementPageCounters(); 00237
00238 incrementPagesOccupiedCounter(); 00239 return allocateFromNewExtent(extentNum, ownerId); 00240 } 00241 00242
00243
00244 undoSegAllocPageWrite(origSegAllocPageId); 00245 00246
00247
00248
00249 if (DelegatingSegment::ensureAllocatedSize( 00250 makePageNum(extentNum + 1,0))) 00251 { 00252
00253 return NULL_PAGE_ID; 00254 } 00255 00256 SegAllocLock newSegAllocLock(segAccessor); 00257 origSegAllocPageId = getSegAllocPageId(iSegAlloc + 1); 00258 segAllocPageId = getSegAllocPageIdForWrite(origSegAllocPageId); 00259 newSegAllocLock.lockExclusive(segAllocPageId); 00260 newSegAllocLock.setMagicNumber(); 00261 SegmentAllocationNode &newNode = newSegAllocLock.getNodeForWrite(); 00262 newNode.nPagesPerExtent = nPagesPerExtent; 00263 newNode.nExtents = 0; 00264 newNode.nextSegAllocPageId = NULL_PAGE_ID; 00265
00266 incrementPagesOccupiedCounter(); 00267 00268
00269 SegmentAllocationNode &writableSegAllocNode = 00270 segAllocLock.getNodeForWrite(); 00271 writableSegAllocNode.nextSegAllocPageId = origSegAllocPageId; 00272 00273
00274
00275
00276 } 00277 } 00278 00279 void RandomAllocationSegmentBase::splitPageId( 00280 PageId pageId,uint &iSegAlloc, 00281 ExtentNum &extentNum,BlockNum &iPageInExtent) const 00282 { 00283
00284 BlockNum iPageInSegAlloc = getLinearBlockNum(pageId) % nPagesPerSegAlloc; 00285 iSegAlloc = getLinearBlockNum(pageId) / nPagesPerSegAlloc; 00286 if (!iPageInSegAlloc) { 00287
00288 extentNum = MAXU; 00289 iPageInExtent = 0; 00290 } else { 00291
00292 --iPageInSegAlloc; 00293 extentNum = 00294 iPageInSegAlloc / nPagesPerExtent + nExtentsPerSegAlloc * iSegAlloc; 00295 iPageInExtent = iPageInSegAlloc % nPagesPerExtent; 00296 } 00297 } 00298 00299 void RandomAllocationSegmentBase::incrementPageCounters() 00300 { 00301 StrictMutexGuard mutexGuard(pageCounterMutex); 00302 00303
00304
00305 if (netDeallocations > 0) { 00306 --netDeallocations; 00307 } else { 00308 ++nPagesOccupiedHighWater; 00309 } 00310 ++nPagesAllocated; 00311 } 00312 00313 void RandomAllocationSegmentBase::incrementPagesOccupiedCounter() 00314 { 00315 StrictMutexGuard mutexGuard(pageCounterMutex); 00316 ++nPagesOccupiedHighWater; 00317 } 00318 00319 void RandomAllocationSegmentBase::decrementPageCounters() 00320 { 00321 StrictMutexGuard mutexGuard(pageCounterMutex); 00322 ++netDeallocations; 00323 --nPagesAllocated; 00324 } 00325 00326 void RandomAllocationSegmentBase::deallocatePageRange( 00327 PageId startPageId, 00328 PageId endPageId) 00329 { 00330 permAssert(startPageId == endPageId); 00331 if (startPageId != NULL_PAGE_ID) { 00332 deallocatePageId(startPageId); 00333 } else { 00334 format(); 00335 } 00336 } 00337 00338 void RandomAllocationSegmentBase::deallocatePageId(PageId pageId) 00339 { 00340 permAssert(pageId != NULL_PAGE_ID); 00341 assert(isPageIdAllocated(pageId)); 00342 00343
00344 BlockId blockId = DelegatingSegment::translatePageId(pageId); 00345 pCache->discardPage(blockId); 00346 00347 ExtentNum extentNum; 00348 BlockNum iPageInExtent; 00349 uint iSegAlloc; 00350 splitPageId(pageId,iSegAlloc,extentNum,iPageInExtent); 00351 permAssert(iPageInExtent); 00352 00353
00354
00355
00356 freePageEntry(extentNum, iPageInExtent); 00357 00358 SegmentAccessor selfAccessor(getTracingSegment(), pCache); 00359 SegAllocLock segAllocLock(selfAccessor); 00360 PageId segAllocPageId = getSegAllocPageId(iSegAlloc); 00361 segAllocLock.lockExclusive(segAllocPageId); 00362 SegmentAllocationNode &segAllocNode = segAllocLock.getNodeForWrite(); 00363 ExtentNum relativeExtentNum = extentNum % nExtentsPerSegAlloc; 00364 segAllocNode.getExtentEntry(relativeExtentNum).nUnallocatedPages++; 00365 permAssert( 00366 segAllocNode.getExtentEntry(relativeExtentNum).nUnallocatedPages 00367 <= nPagesPerExtent); 00368 00369 decrementPageCounters(); 00370 } 00371 00372 Segment::AllocationOrder RandomAllocationSegmentBase::getAllocationOrder() const 00373 { 00374 return RANDOM_ALLOCATION; 00375 } 00376 00377 BlockId RandomAllocationSegmentBase::translatePageId(PageId pageId) 00378 { 00379 assert( 00380 const_cast<RandomAllocationSegmentBase *>(this)->isPageIdValid(pageId)); 00381 00382 return DelegatingSegment::translatePageId(pageId); 00383 } 00384 00385 bool RandomAllocationSegmentBase::testPageId( 00386 PageId pageId, 00387 bool testAllocation, 00388 bool thisSegment) 00389 { 00390 if (DelegatingSegment::isPageIdAllocated(pageId)) { 00391 return false; 00392 } 00393 00394 uint iSegAlloc; 00395 ExtentNum extentNum; 00396 BlockNum iPageInExtent; 00397 splitPageId(pageId,iSegAlloc,extentNum,iPageInExtent); 00398 if (!iPageInExtent) { 00399
00400
00401
00402 if (testAllocation) { 00403 return false; 00404 } else { 00405 return true; 00406 } 00407 } 00408 PageOwnerId ownerId = getPageOwnerId(pageId, thisSegment); 00409 return (ownerId != UNALLOCATED_PAGE_OWNER_ID); 00410 } 00411 00412 bool RandomAllocationSegmentBase::isPageIdValid(PageId pageId) 00413 { 00414 return testPageId(pageId,false,true); 00415 } 00416 00417 bool RandomAllocationSegmentBase::isPageIdAllocated(PageId pageId) 00418 { 00419 return testPageId(pageId,true,true); 00420 } 00421 00422 BlockNum RandomAllocationSegmentBase::getAllocatedSizeInPages() 00423 { 00424 return nPagesAllocated; 00425 } 00426 00427 void RandomAllocationSegmentBase::countAllocatedPages() 00428 { 00429 StrictMutexGuard mutexGuard(pageCounterMutex); 00430 PageId origSegAllocPageId = getFirstSegAllocPageId(); 00431 do { 00432 SharedSegment allocNodeSegment; 00433 PageId segAllocPageId = 00434 getSegAllocPageIdForRead(origSegAllocPageId, allocNodeSegment); 00435 00436 PageId nextSegAllocPageId; 00437 tallySegAllocNodePages( 00438 segAllocPageId, 00439 allocNodeSegment, 00440 nextSegAllocPageId); 00441
00442 ++nPagesOccupiedHighWater; 00443 00444 origSegAllocPageId = nextSegAllocPageId; 00445 } while (origSegAllocPageId != NULL_PAGE_ID); 00446 } 00447 00448 BlockNum RandomAllocationSegmentBase::getNumPagesOccupiedHighWater() 00449 { 00450 return nPagesOccupiedHighWater; 00451 } 00452 00453 void RandomAllocationSegmentBase::tallySegAllocNodePages( 00454 PageId segAllocPageId, 00455 SharedSegment allocNodeSegment, 00456 PageId &nextSegAllocPageId) 00457 { 00458 SegmentAccessor segAccessor(allocNodeSegment, pCache); 00459 SegAllocLock segAllocLock(segAccessor); 00460 00461
00462
00463 segAllocLock.lockExclusive(segAllocPageId); 00464 SegmentAllocationNode const &node = segAllocLock.getNodeForRead(); 00465 uint i; 00466 for (i = 0; i < node.nExtents; i++) { 00467
00468 BlockNum numPages = 00469 nPagesPerExtent 00470 - node.getExtentEntry(i).nUnallocatedPages; 00471 nPagesAllocated += (numPages - 1); 00472 nPagesOccupiedHighWater += numPages; 00473 } 00474 nextSegAllocPageId = node.nextSegAllocPageId; 00475 } 00476 00477 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/segment/RandomAllocationSegmentBase.cpp#12 $"); 00478 00479