首頁 > 軟體

C++實現頁面的緩衝區管理器

2022-08-01 22:03:34

1. 實驗目標

本次實驗要實現一個頁面的緩衝區管理器。

具體要實現以下的函數:

~BufMgr():

清除所有髒頁並釋放緩衝池和 BufDesc 表

void advanceClock():

用來找到下一個時鐘的位置

void allocBuf(FrameId& frame):

使用時鐘演演算法分配自由幀;如有必要,將髒頁寫回磁碟。

void readPage(File* file, const PageId PageNo, Page*& page)

通過呼叫 lookup()方法檢查頁是否已經在緩衝池中。當頁不在緩衝池中可以在雜湊表上丟擲 HashNotFoundException 以獲取幀編號。

void unPinPage(File* file, const PageId PageNo, const bool dirty)

減少一個頁面的佔用次數

void allocPage(File* file, PageId& PageNo, Page*& page)

通過呼叫 file->allocatePage()方法在指定的檔案中分配一個空頁。此方法將返回新分配的頁。然後呼叫 allocBuf()以獲取緩衝池幀。接下來,將一個條目插入到雜湊表中,並在幀上呼叫 Set(),以正確設定它。

void disposePage(File* file, const PageId pageNo)

功能是釋放一個頁面

void flushFile(File* file)

功能是找到含有對應檔案的頁面,並釋放

2. 程式碼實現

BufMgr::~BufMgr() {
    delete hashTable;
    delete[] bufPool;
    delete[] bufDescTable;
}

直接呼叫 delete 刪除雜湊表、緩衝池、緩衝池表

void BufMgr::advanceClock() {
    clockHand++;
    if (clockHand >= numBufs) {
        clockHand %= numBufs;
    }
}

將時鐘提前到緩衝池的下一幀。

如果指標超過了最大值,進行取模操作。

void BufMgr::allocBuf(FrameId &frame) {
    unsigned pinned = 0;
    while (true) {
        advanceClock();
        if (!bufDescTable[clockHand].valid) {
            frame = clockHand;
            return;
        }
        if (bufDescTable[clockHand].refbit) {
            bufDescTable[clockHand].refbit = false;
            continue;
        }
        if (bufDescTable[clockHand].pinCnt) {
            pinned++;
            if (pinned == numBufs) {
                throw BufferExceededException();
            } else {
                continue;
            }
        }
        if (bufDescTable[clockHand].dirty) {
            bufDescTable[clockHand].file->writePage(bufPool[clockHand]);
            bufDescTable[clockHand].dirty = false;
        }
        frame = clockHand;
        if (bufDescTable[clockHand].valid) {
            try {
                hashTable->remove(bufDescTable[clockHand].file, bufDescTable[clockHand].pageNo);
            }
            catch (HashNotFoundException &) {
            }
        }
        break;
    }
}

遍歷棧區尋找可用的頁面。如果是沒有被使用過的頁面,直接進行分配。如果緩衝區所有的頁面都被佔用,那麼會進行報錯 BufferExceededException()。如果找到髒頁,會將它寫回磁碟,並將髒頁標記給清除。如果不是髒頁,那麼就進行分配操作。如果它在雜湊表中要將它移除。

void BufMgr::readPage(File *file, const PageId pageNo, Page *&page) {
    FrameId frame;
    try {
        hashTable->lookup(file, pageNo, frame);
        bufDescTable[frame].refbit = true;
        bufDescTable[frame].pinCnt++;
        page = (bufPool + frame);
    } catch (HashNotFoundException &) {
        allocBuf(frame);
        bufPool[frame] = file->readPage(pageNo);
        hashTable->insert(file, pageNo, frame);
        bufDescTable[frame].Set(file, pageNo);
        page = (bufPool + frame);
    }
}

如果頁面在緩衝池中,增加它的佔用次數,呼叫 page 返回指向該頁面的指標。

如果頁面不在緩衝池中,那麼將頁面讀取到緩衝池,插入雜湊表中,呼叫 set 正確設定該介面,呼叫 page 返回指向該頁面的指標。

void BufMgr::unPinPage(File *file, const PageId pageNo, const bool dirty) {
    FrameId frame;
    try {
        hashTable->lookup(file, pageNo, frame);
    } catch (HashNotFoundException &) {
        //沒有該頁面
        cerr << "Warning: unpinning a nonexistent page" << endl;
        return;
    }
    //找到頁面
    if (bufDescTable[frame].pinCnt > 0) {
        bufDescTable[frame].pinCnt--;
        if (dirty) {
            bufDescTable[frame].dirty = true;
        }
    } else {
        //pin = 0,丟擲異常
        throw PageNotPinnedException(bufDescTable[frame].file->filename(), bufDescTable[frame].pageNo, frame);
    }
}

如果緩衝池中沒有該頁面,進行異常提示。

如果在緩衝池中,那麼將它的佔用次數減少。如果佔用次數為 0,進行報錯。

void BufMgr::flushFile(const File *file) {
    for (FrameId fi = 0; fi < numBufs; fi++) {
        if (bufDescTable[fi].file == file) {
            if (!bufDescTable[fi].valid) {
                throw BadBufferException(fi, bufDescTable[fi].dirty, bufDescTable[fi].valid, bufDescTable[fi].refbit);
            }
            if (bufDescTable[fi].pinCnt > 0) {
                throw PagePinnedException(file->filename(), bufDescTable[fi].pageNo, fi);
            }
            if (bufDescTable[fi].dirty) {
                bufDescTable[fi].file->writePage(bufPool[fi]);
                bufDescTable[fi].dirty = false;
            }
            hashTable->remove(file, bufDescTable[fi].pageNo);
            bufDescTable[fi].Clear();
        }
    }
}

遍歷整個表,找到含有對應頁面的緩衝頁,移除並清空該頁面。如果頁面是髒頁,則將其寫回磁碟,初始化髒頁標記。如果頁面被佔用或者頁面不可用,則進行報錯。

void BufMgr::allocPage(File *file, PageId &pageNo, Page *&page) {
    FrameId frame;
    Page p = file->allocatePage();
    allocBuf(frame);
    bufPool[frame] = p;
    pageNo = p.page_number();
    hashTable->insert(file, pageNo, frame);
    bufDescTable[frame].Set(file, pageNo);
    page = bufPool + frame;
}

掉用 allocatePage()分配一個新頁面,加入雜湊表,呼叫 set(),返回該頁面指標。

void BufMgr::disposePage(File *file, const PageId PageNo) {
    FrameId frame;
    try {
        hashTable->lookup(file, PageNo, frame);
        hashTable->remove(file, PageNo);
        bufDescTable[frame].Clear();
    } catch (HashNotFoundException &) {
    }
    file->deletePage(PageNo);
}

刪除一個頁面。如果它在緩衝池中,要將緩衝內容一併刪除。

3.實驗結果

12個樣例均能通過,實驗結果如下:

me].Clear();
} catch (HashNotFoundException &) {
}
file->deletePage(PageNo);
}

刪除一個頁面。如果它在緩衝池中,要將緩衝內容一併刪除

到此這篇關於C++實現頁面的緩衝區管理器的文章就介紹到這了,更多相關C++緩衝區管理器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com