📄 ck_generation.cxx
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <disk/DiskNode.hxx>#include <disk/PagePot.hxx>#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/Check.hxx>#include <kerninc/Checkpoint.hxx>#include <kerninc/Persist.hxx>voidCoreGeneration::Init(){ bzero(this, sizeof(*this)); oidTree = CkNIL; nextNodeLid = UNDEF_LID;}/************************** * Log frame management **************************/boolCoreGeneration::ReserveFrame(){ /* If we have reserved enough already that we are over the limit, * don't let us reserve any more: */ if (rsrv.nFrames - release.nFrames >= Checkpoint::ckGenLimit) return false; /* If no space is currently available in the log, declare a checkpoint. */ if ( Checkpoint::ReserveLogFrame() == false ) return false; rsrv.nFrames++; return true;}boolCoreGeneration::ReserveDirent(uint32_t count){ assert ( count < CkptDirPage::maxDirEnt ) ; assert ( count <= EROS_OBJECTS_PER_FRAME ) ; if ((rsrv.nDirent + count) > (rsrv.nDirFrame * CkptDirPage::maxDirEnt)) { if (ReserveFrame() == false) return false; rsrv.nDirFrame++; } assert(rsrv.nPage + rsrv.nDirFrame + rsrv.nNodeFrame == rsrv.nFrames); assert( (rsrv.nDirent + count) <= (rsrv.nDirFrame * CkptDirPage::maxDirEnt) ); rsrv.nDirent += count; return true;}boolCoreGeneration::ReserveNode(uint32_t count){ assert ( count <= DISK_NODES_PER_PAGE ) ; assert ( count <= EROS_OBJECTS_PER_FRAME ) ; if ((rsrv.nNode + count) > rsrv.nNodeFrame * DISK_NODES_PER_PAGE) { if (ReserveFrame() == false) return false; rsrv.nNodeFrame++; } assert(rsrv.nPage + rsrv.nDirFrame + rsrv.nNodeFrame == rsrv.nFrames); assert( (rsrv.nNode + count) <= (rsrv.nNodeFrame * DISK_NODES_PER_PAGE) ); rsrv.nNode += count; return true;}bool CoreGeneration::ReserveDataPage(){ if (ReserveFrame()) { rsrv.nPage++; return true; } return false;}voidCoreGeneration::UnreserveFrame(){ Checkpoint::nReservedLogFrame--; rsrv.nFrames--;}voidCoreGeneration::UnreservePage(){ UnreserveFrame(); rsrv.nPage--;}void CoreGeneration::UnreserveNode(){ rsrv.nNode--; if (rsrv.nNode == (rsrv.nNodeFrame - 1) * DISK_NODES_PER_PAGE) { UnreserveFrame(); rsrv.nNodeFrame--; }}void CoreGeneration::UnreserveDirent(){ rsrv.nDirent--; if (rsrv.nDirent == (rsrv.nDirFrame - 1) * CkptDirPage::maxDirEnt) { UnreserveFrame(); rsrv.nDirFrame--; }}lid_tCoreGeneration::AllocateLid(lid_t ll){ assert (rsrv.nFrames > alloc.nFrames); if (ll == UNDEF_LID) { ll = Checkpoint::FindFreeFrame(); assert (Checkpoint::FrameIsEmpty(ll)); alloc.nFrames++; } Checkpoint::AllocateLid(ll); return ll;}boolCoreGeneration::DeallocateLid(lid_t ll){ if (Checkpoint::DeallocateLid(ll) == false) return false; release.nFrames++; return true;}voidCoreGeneration::FinishActiveNodeFrame(){ if (nextNodeLid != UNDEF_LID) { if (DeallocateLid(nextNodeLid)) release.nNodeFrame++; nextNodeLid = UNDEF_LID; }}/* Allocate storage for the object described by /CoreDirent/, if any * is needed. Populate the CoreDirent with the resulting object * location. */voidCoreGeneration::Allocate(CoreDirent* cde){#ifndef NDEBUG CheckConsistency(false);#endif if (CONTENT_LID(cde->lid)) /* already allocated */ return; switch(cde->type) { case FRM_TYPE_NODE: { if (nextNodeLid == UNDEF_LID) { /* This is the EXTRA allocation that will keep the frame from * being deallocated if all nodes in it are released before we * are done with it. */ nextNodeLid = AllocateLid(); assert (nextNodeLid % EROS_OBJECTS_PER_FRAME == 0); alloc.nNodeFrame++; /* Zeroing the log frame is not necessary for correctness. * The purpose of doing so is to ensure that in most cases * fetching the frame will not entail a disk I/O operation. * The attempt to zero the page will occasionally cause the * ager to run, resulting in a yield. In that event we will * re-enter WriteNodeToLog(), which will re-invoke this * routine. We will conclude at that point that nextNodeLid * is not UNDEF_LID, proceed to stash the node in this frame, * and eat the extra I/O. */ Persist::ZeroCkFrame(nextNodeLid); } alloc.nNode++; cde->lid = nextNodeLid; nextNodeLid = AllocateLid(nextNodeLid); nextNodeLid++; if ((nextNodeLid % EROS_OBJECTS_PER_FRAME) == DISK_NODES_PER_PAGE) { assertex ((void*)(this->index), (alloc.nNode % DISK_NODES_PER_PAGE) == 0); FinishActiveNodeFrame(); } break; } case FRM_TYPE_DPAGE: { alloc.nPage++; cde->lid = AllocateLid(); /* We do not bother to zero this frame, as a complete page will * be written. */ break; } default: /* Object is a zero object. Allocate no storage for it. */ ; }#ifndef NDEBUG CheckConsistency(false);#endif}/* Release any allocated storage currently associated with this * object, but not the storage for the directory entry itself. */voidCoreGeneration::Release(CoreDirent* cde){#ifndef NDEBUG CheckConsistency(false);#endif assert(cde->lid != DEAD_LID); if (!CONTENT_LID(cde->lid) && cde->lid != UNDEF_LID) return; switch(cde->type) { case FRM_TYPE_NODE: { if (cde->lid == UNDEF_LID) { UnreserveNode(); } else { release.nNode++; if (DeallocateLid(cde->lid)) release.nNodeFrame++; } break; } case FRM_TYPE_DPAGE: { if (cde->lid == UNDEF_LID) { UnreservePage(); } else { release.nPage++; DeallocateLid(cde->lid); } break; } default: /* Object is a zero object. There is no storage to release. */ assert(cde->lid == ZERO_LID); } cde->lid = DEAD_LID; /* for paranoia's sake */#ifndef NDEBUG CheckConsistency(false);#endif}boolCoreGeneration::ReclaimLogPage(){ if (canReclaim == false) return false; assert (alloc.nFrames == rsrv.nFrames); if (alloc.nFrames == release.nFrames) return false; uint32_t curReleased = release.nFrames; do { if (oidTree != CkNIL) { CoreDirent *cde = oidTree; Release(cde); RemoveFromOidMap(cde); delete cde; } } while (release.nFrames == curReleased); return true;}voidCoreGeneration::Reclaim(){ while (oidTree != CkNIL) { CoreDirent *cde = oidTree; Release(cde); RemoveFromOidMap(cde); delete cde; }}/* Check the consistency of the per-generation variables, including * verifying that the reserved and allocated counts match if appropriate. */boolCoreGeneration::CheckConsistency(bool allAllocated){ bool ckresult = true; REQUIRE(rsrv.nPage + rsrv.nDirFrame + rsrv.nNodeFrame == rsrv.nFrames); REQUIRE(rsrv.nNode <= rsrv.nNodeFrame * DISK_NODES_PER_PAGE); REQUIRE(rsrv.nNode + DISK_NODES_PER_PAGE > rsrv.nNodeFrame * DISK_NODES_PER_PAGE); REQUIRE(rsrv.nDirent <= rsrv.nDirFrame * CkptDirPage::maxDirEnt); REQUIRE(rsrv.nDirent + CkptDirPage::maxDirEnt > rsrv.nDirFrame * CkptDirPage::maxDirEnt); REQUIRE(alloc.nPage + alloc.nNodeFrame <= alloc.nFrames); REQUIRE(alloc.nNode <= alloc.nNodeFrame * DISK_NODES_PER_PAGE); /* Following is tricky. Due to the extra allocation on the active * node frame in the checkpoint area, it's actually possible for all * of the contained nodes to get deallocated long before the node frame * gets deallocated. This only occurs when lastNodeLid != * UNDEF_LID. */ if (nextNodeLid == UNDEF_LID) REQUIRE(alloc.nNode + DISK_NODES_PER_PAGE > alloc.nNodeFrame * DISK_NODES_PER_PAGE); else REQUIRE(alloc.nNode + 2*DISK_NODES_PER_PAGE > alloc.nNodeFrame * DISK_NODES_PER_PAGE); REQUIRE(alloc.nCoreDirent <= rsrv.nDirent); REQUIRE(alloc.nNode <= rsrv.nNode); REQUIRE(alloc.nPage <= rsrv.nPage); REQUIRE(alloc.nNodeFrame <= rsrv.nNodeFrame); REQUIRE(alloc.nFrames <= rsrv.nFrames); REQUIRE(release.nNode <= alloc.nNode); REQUIRE(release.nPage <= alloc.nPage); REQUIRE(release.nDirFrame <= alloc.nDirFrame); REQUIRE(release.nNodeFrame <= alloc.nNodeFrame); REQUIRE(release.nFrames <= alloc.nFrames); if (canReclaim) REQUIRE(release.nDirFrame == alloc.nDirFrame); if (canReclaim || allAllocated) { REQUIRE(alloc.nCoreDirent == rsrv.nDirent); REQUIRE(alloc.nNode == rsrv.nNode); REQUIRE(alloc.nPage == rsrv.nPage); REQUIRE(alloc.nNodeFrame == rsrv.nNodeFrame); REQUIRE(alloc.nFrames == rsrv.nFrames); REQUIRE(alloc.nPage + alloc.nNodeFrame + alloc.nDirFrame == alloc.nFrames); } return ckresult;}#ifdef OPTION_DDBvoidCoreGeneration::ddb_showalloc(){ extern void db_printf(const char *fmt, ...); db_printf("Ck%d: Rsrv nNode= %6d nPage= %6d\n", index, rsrv.nNode, rsrv.nPage); db_printf(" Rsrv nDirFrame=%6d nNdFrame= %6d nFrames= %6d\n", rsrv.nDirFrame, rsrv.nNodeFrame, rsrv.nFrames); db_printf(" Rsrv nDirent= %6d\n", rsrv.nDirent); db_printf(" Aloc nNode= %6d nPage= %6d\n", alloc.nNode, alloc.nPage); db_printf(" Aloc nDirFrame=%6d nNdFrame= %6d nFrames= %6d\n", alloc.nDirFrame, alloc.nNodeFrame, alloc.nFrames); db_printf(" Aloc nCrDirent=%6d\n", alloc.nCoreDirent); db_printf(" Rels nNode= %6d nPage= %6d\n", release.nNode, release.nPage); db_printf(" Rels nDirFrame=%6d nNdFrame= %6d nFrames= %6d\n", release.nDirFrame, release.nNodeFrame, release.nFrames);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -