?? buffer.cpp
字號:
/******************************************************************
** 文件名: Buffer.cpp
** Copyright (c) 2001-2002 計算機99F MiniSQL開發小組其一
** 創建人: 郭振宇
** 日 期: 2001-11-28
** 修改人: 郭振宇
** 日 期: 2002-01-05
** 描 述: 定義了MiniSQL buffer模塊所有類和結構
** 版 本: 1.00
******************************************************************/
#include"Buffer.h"
//-------------------------------------------------------
_M_Buffer Buffer;
unsigned int SizeOfPageHead = sizeof(_TB_PAGEHEAD);
unsigned int BTreeNodeSize = (FILE_PAGESIZE - SizeOfPageHead)/4;
//-------------------------------------------------------
// 初始化
void _TB_PAGEHEAD::Initial(unsigned long mypageid,bool myisfixed)
{
this->ulPageID = mypageid;
this->bIsFixed = myisfixed;
}
//-------------------------------------------------------
// 初始化
void _TB_FILECOND::InitialFileCond()
{
this->ulPageTotal = 1;
this->DelFirst.Initialize();
this->DelLast.Initialize();
this->NewInsert.ulFilePageID = 1;
this->NewInsert.uiOffset = SizeOfPageHead;
}
//-------------------------------------------------------
// 文件頭信息(若頁PageID==0,則有,否則返回空)
_TB_FILECOND* _M_Page::Ptr2FileCond()
{
return (_TB_FILECOND* )((char*)this->Ptr2PageBegin + SizeOfPageHead);
}
//-------------------------------------------------------
// 成員初始化,開辟內存空間
_M_Page::_M_Page()
{
this->Ptr2PageBegin = malloc(FILE_PAGESIZE);
if(!this->Ptr2PageBegin) throw 1000; // 內存開辟失敗
this->Ptr2Head = (_TB_PAGEHEAD*)this->Ptr2PageBegin;
this->ulFilePageID = 0;
this->uiFileID = 0;
}
//-------------------------------------------------------
// 釋放內存空間
_M_Page::~_M_Page()
{
this->ulFilePageID = 0;
this->uiFileID = 0;
free(this->Ptr2PageBegin);
this->Ptr2Head = 0;
this->Ptr2PageBegin = 0;
}
//-------------------------------------------------------
//**從文件中調入頁至開辟好的內存空間中
void _M_Page::LoadFromFile(unsigned int fileid,unsigned long filepageid)
{
this->uiFileID = fileid;
this->ulFilePageID = filepageid;
if( Buffer.GetIsNew(fileid) ) // 文件新建
{
this->Ptr2Head->Initial(filepageid,1); // 初始化頁頭信息
this->Ptr2FileCond()->InitialFileCond(); // 初始化文件頭信息
Buffer.SetIsNew(fileid,0); // 設置使文件不再為新建狀態(以免下次訪問這個內存頁又要進行頭信息初始化)
}
else if( filepageid >= Buffer.GetPageTotal(fileid) ) // 比現有文件總頁面要多,那么開辟新的頁面加到文件末尾
{
if( filepageid - Buffer.GetPageTotal(fileid) > 0) throw 1004; // 頁編號比現有文件最后一個頁編號+1 還要大(浪費磁盤空間)
this->Ptr2Head->Initial(filepageid,0); // 初始化頁頭信息
Buffer.AddPageTotal(fileid,1); // 使文件總頁數加1
}
else // 其他情況
{
lseek(Buffer.GetPtr2File(fileid),filepageid*FILE_PAGESIZE,0); // 定位到將要取出的文件頁的首地址
int temp = read(Buffer.GetPtr2File(fileid),this->Ptr2PageBegin,FILE_PAGESIZE); // 讀到內存中
if( temp!= FILE_PAGESIZE ) throw 1031; // 讀失敗
}
}
//-------------------------------------------------------
//**把內存中的頁寫回到文件中
void _M_Page::Back2File() const
{
int temp = 0;
temp = lseek(Buffer.GetPtr2File(this->uiFileID),this->ulFilePageID*FILE_PAGESIZE,0);
if(temp==-1L) throw 1005;
temp = write(Buffer.GetPtr2File(this->uiFileID),this->Ptr2PageBegin,FILE_PAGESIZE); // 寫回文件
if(temp!= FILE_PAGESIZE) throw 1002; // 寫失敗
}
//-------------------------------------------------------
// 成員初始化
_M_PageInfo::_M_PageInfo()
{
this->bIsLastUsed = 0;
this->bIsModified = 0;
this->Ptr2Page = 0;
}
//-------------------------------------------------------
// 析構,根據bIsModified決定是否需要寫會文件
_M_PageInfo::~_M_PageInfo()
{
if(this->Ptr2Page){
if(this->Ptr2Page->uiFileID && this->Ptr2Page->ulFilePageID==0)
// 把文件頁總數寫到磁盤中,已備下次讀取
this->Ptr2Page->Ptr2FileCond()->ulPageTotal = Buffer.GetPageTotal(this->Ptr2Page->uiFileID);
if(this->Ptr2Page->uiFileID && this->bIsModified){ // 若為臟頁,寫回
this->Ptr2Page->Back2File();
}
delete this->Ptr2Page;
this->Ptr2Page = 0;
}
this->bIsLastUsed = 0;
this->bIsModified = 0;
}
//-------------------------------------------------------
// 頁替換、開辟等
void _M_PageInfo::UpdatePageInfo(unsigned int fileid,unsigned long filepageid)
{
if( this->bIsModified) // 若為臟頁,寫回
this->Ptr2Page->Back2File();
this->bIsLastUsed = 1;
this->bIsModified = 0;
if( !this->Ptr2Page ){ // 尚未開辟內存空間
this->Ptr2Page = new _M_Page; // 新的內存頁對象
}
// 若文件新建 或者 該頁為文件第0頁 后者 該頁在原來文件中不存在 則要求寫回
if( Buffer.GetIsNew(fileid) || filepageid >= Buffer.GetPageTotal(fileid) || filepageid==0 )
this->bIsModified = 1;
this->Ptr2Page->LoadFromFile(fileid,filepageid); // 讀到內存中
}
//-------------------------------------------------------
// 取得文件頭信息地址
_TB_FILECOND* _M_PageInfo::GetPtr2FileCond() const
{
return this->Ptr2Page->Ptr2FileCond();
}
//-------------------------------------------------------
// 取得頁頭信息地址
_TB_PAGEHEAD* _M_PageInfo::GetPtr2Head() const
{
return this->Ptr2Page->Ptr2Head;
}
//-------------------------------------------------------
// 取得所分配的內存頁目前內容所屬的文件編號
unsigned int _M_PageInfo::GetFileID() const
{
return this->Ptr2Page->uiFileID;
}
//-------------------------------------------------------
// 設置新的文件編號(拋棄頁時設為0即可)
void _M_PageInfo::SetFileID(unsigned int fileid)
{
this->Ptr2Page->uiFileID = fileid;
}
//-------------------------------------------------------
// 取得所分配的內存頁目前內容在文件中的頁編號
unsigned long _M_PageInfo::GetFilePageID() const
{
return this->Ptr2Page->ulFilePageID;
}
//-------------------------------------------------------
// 成員初始化
_M_Clock::_M_Clock()
{
this->uiClockSize = MEM_PAGEAMOUNT;
this->uiCurrClockPtr = 1;
for(unsigned int i=0;i<=this->uiClockSize;i++)
{
this->Ptr2MemPageInfo[i] = new _M_PageInfo;
}
}
//-------------------------------------------------------
// 析構
_M_Clock::~_M_Clock()
{
for(unsigned int i=0;i<=this->uiClockSize;i++)
delete this->Ptr2MemPageInfo[i] ;
}
//-------------------------------------------------------
//**查找Clock中尚未分配內存空間的頁
unsigned int _M_Clock::GetNullPage()
{
for(unsigned int i=this->uiCurrClockPtr;i<=this->uiClockSize;i++)
{
if( !this->Ptr2MemPageInfo[i]->Ptr2Page ) // 尚未分配內存頁
{
this->uiCurrClockPtr = i;
return this->uiCurrClockPtr;
}
}
return 0;
}
//-------------------------------------------------------
//**查找Clock中已經被拋棄的頁
unsigned int _M_Clock::GetFreePage()
{
for(unsigned int i=1;i<=this->uiClockSize;i++)
{
// 被拋棄內存頁已經把文件編號置為 0 做為標記
if( this->Ptr2MemPageInfo[i]->Ptr2Page && !this->Ptr2MemPageInfo[i]->GetFileID() )
{
this->uiCurrClockPtr = i;
return this->uiCurrClockPtr;
}
}
return 0;
}
//-------------------------------------------------------
// 查找Clock中最近一頁可被替換的頁
unsigned int _M_Clock::GetSwapPage(unsigned int fileid)
{
if(! this->GetFreePage() ) // 查找被拋棄的內存頁
// 查找Clock中最早打開的文件所占用的內存頁,如果是常駐內存頁則關閉該文件(該寫回的寫回)
if(! this->NR_Search(fileid) )
if(! this->U_M_Search(0,0,0) ) // 上次沒有用,沒有被修改,不變動bIsLastUsed,返回符合這樣條件的內存頁
if(! this->U_M_Search(0,1,1) ) // 上次沒有用,有被修改,變動bIsLastUsed,返回符合這樣條件的內存頁
if(! this->U_M_Search(0,0,0) ) // 上次沒有用,沒有被修改,不變動bIsLastUsed,返回符合這樣條件的內存頁
this->U_M_Search(0,1,1); // 上次沒有用,有被修改,變動bIsLastUsed,返回符合這樣條件的內存頁
return this->uiCurrClockPtr;
}
//-------------------------------------------------------
// 查找Clock中最早打開的文件所占用的內存頁,如果是常駐內存頁則關閉該文件(該寫回的寫回)
// 所有打開的文件已經由_M_Buffer類組織成鏈表
unsigned int _M_Clock::NR_Search(unsigned int tarfileid)
{
unsigned int NR_FileIDTemp = 0; // 臨時文件編號
unsigned int NR_FileID = 20000; // 欲替換的內存頁所屬文件編號(程序運行期分配),20000為不可能的一個數字(打開20000個文件方有可能)
unsigned int ClockPtr = 0; // 與替換的頁編號
unsigned int relativefileid = Buffer[tarfileid]->GetRelativeFileID(); // 取得關聯文件編號
for(unsigned int i=1;i<=this->uiClockSize;i++)
{
NR_FileIDTemp = this->Ptr2MemPageInfo[i]->GetFileID();
// 文件編號不能為當前文件編號及其關聯文件的編號,在符合這個條件的基礎上,文件編號越小,越早打開,所以更適合被替換
if( NR_FileIDTemp < NR_FileID && NR_FileIDTemp != tarfileid && NR_FileIDTemp != relativefileid )
{
NR_FileID = NR_FileIDTemp;
ClockPtr = i;
}
}
if( NR_FileID != 20000 )
{
// 如果被替換頁是第 0 頁,則關閉該文件及其關聯文件
if( this->Ptr2MemPageInfo[ClockPtr]->GetFilePageID() == 0 )
Buffer[NR_FileID]->Close();
this->uiCurrClockPtr = ClockPtr;
return this->uiCurrClockPtr;
}
else
return 0;
}
//-------------------------------------------------------
// Clock算法實現,通過U_M_Search()四次調用,完成Clock算法
unsigned int _M_Clock::U_M_Search(bool islastused,bool ismodified,bool changeused)
{
for(unsigned int i=1;i<=this->uiClockSize;i++)
{
if( this->Ptr2MemPageInfo[this->uiCurrClockPtr]->GetPtr2Head()->bIsFixed == 0 &&
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->bIsLastUsed == islastused &&
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->bIsModified == ismodified )
return this->uiCurrClockPtr;
else
{
if( changeused ) this->Ptr2MemPageInfo[this->uiCurrClockPtr]->bIsLastUsed = 0;
this->uiCurrClockPtr = (this->uiCurrClockPtr+1)%this->uiClockSize;
if(!this->uiCurrClockPtr)
this->uiCurrClockPtr = this->uiClockSize;
}
}
return 0;
}
//-------------------------------------------------------
// 查找已經存在的頁(假設要找的頁已經存在的話)
unsigned int _M_Clock::GetExsitPage(unsigned int fileid,unsigned long filepageid)
{
if( this->Ptr2MemPageInfo[this->uiCurrClockPtr]->Ptr2Page &&
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->GetFileID() == fileid &&
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->GetFilePageID() == filepageid )
return this->uiCurrClockPtr;
for(unsigned int i=1;i<=this->uiClockSize;i++)
{
if(!this->Ptr2MemPageInfo[i]->Ptr2Page) break;
if( this->Ptr2MemPageInfo[i]->GetFileID() == fileid &&
this->Ptr2MemPageInfo[i]->GetFilePageID() == filepageid )
{
this->uiCurrClockPtr = i;
return this->uiCurrClockPtr;
}
}
return 0;
}
//-------------------------------------------------------
// 根據文件編號和頁號取得內存頁(通過上面各種方法)
_M_PageInfo* _M_Clock::GetTargetPage(unsigned int fileid,unsigned long filepageid)
{
unsigned int tempint = this->GetExsitPage(fileid,filepageid); // 先找內存頁是否已經存在
if(tempint) return this->Ptr2MemPageInfo[tempint];
tempint = this->GetNullPage(); // 看看有沒有空的內存頁尚未開辟使用
if(!tempint) tempint = this->GetSwapPage(fileid); // 得到替換頁
this->Ptr2MemPageInfo[tempint]->UpdatePageInfo(fileid,filepageid); // 調入文件頁至內存,并更新相關信息
return this->Ptr2MemPageInfo[tempint];
}
//-------------------------------------------------------
// 拋棄文件所屬內存頁(適用于欲刪除一個文件的時候)
void _M_Clock::CloseFilePages(unsigned int fileid)
{
for(unsigned int i=1;i<=this->uiClockSize;i++)
{
if( !this->Ptr2MemPageInfo[i]->Ptr2Page ) break;
if( this->Ptr2MemPageInfo[i]->GetFileID() == fileid )
{
if( this->Ptr2MemPageInfo[i]->bIsModified )
this->Ptr2MemPageInfo[i]->Ptr2Page->Back2File();
this->Ptr2MemPageInfo[i]->bIsModified = 0;
this->Ptr2MemPageInfo[i]->SetFileID(0);
}
}
return;
}
//-------------------------------------------------------
// 設置當前頁使之為臟頁
void _M_Clock::SetPageModified()
{
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->bIsModified = 1;
}
//-------------------------------------------------------
// 初始化,打開和新建文件,若當前文件開的太多,導致無法再打開新文件,可自動關閉最早打開的文件
_M_File::_M_File(const char *name,unsigned int fileid)
{
this->uiFileID = fileid;
this->IsNew = 0;
this->ulPageTotal = 1;
strcpy(this->FileName,name);
this->Ptr2File = open(name,_O_BINARY|O_RDWR,0664);
if(this->Ptr2File==-1){ // 文件不存在
this->Ptr2File = open(name,_O_BINARY|O_RDWR|O_CREAT,0664); // 新建文件(打開文件)
if(this->Ptr2File==-1) // 文件不能被打開(新建)
{
if( Buffer._F_First)
Buffer._F_First->Close(); // 關閉最早打開的文件
this->Ptr2File = open(name,_O_BINARY|O_RDWR|O_CREAT,0664); // 新建文件(打開文件)
if(this->Ptr2File==-1) // 文件不能被新建(打開)
throw 1006; // 文件還是不能被打開(新建),可能為磁盤空間不足等意外
}
this->IsNew = 1;
}
this->_F_Next = 0;
}
//-------------------------------------------------------
// 取得相關文件,由于一個表包含兩個文件(.idx,.dbf),故查找關聯的文件編號
unsigned int _M_File::GetRelativeFileID() const
{
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -