📄 buffer.cpp
字号:
#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;
}
//////////////////////////////////////////////////////////////////
//class _M_Page
//取得文件头信息
_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::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; // 写失败
}
//从文件中调入页至开辟好的内存空间中
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)
{
//cout<<"";
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)
{
//cout<<"
throw 1031; // 读失败
//return;
}
}
}
//////////////////////////////////////////////////////////////////
//class _M_Clock
//construct _M_Clock 成员初始化
_M_Clock::_M_Clock()
{
uiClockSize=MEM_PAGEAMOUNT;
uiCurrClockPtr=1;
for(int i=0;i<=MEM_PAGEAMOUNT;i++)
{
Ptr2MemPageInfo[i]= new _M_PageInfo;
}
}
//destruct _M_Clock 析构
_M_Clock::~_M_Clock()
{
for(unsigned int i=0;i<=this->uiClockSize;i++)
delete 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];
}
//关闭内存中的文件页 文件id==fileid
void _M_Clock::CloseFilePages(unsigned int fileid)
{
for(unsigned int i=1;i<this->uiClockSize;i++)
{
if( !this->Ptr2MemPageInfo[i]->Ptr2Page ) break;
if(Ptr2MemPageInfo[i]->GetFileID()==fileid)
{
//如果是dirty data写回磁盘 并将 ifmodified 改回0;
if(Ptr2MemPageInfo[i]->bIsModified)
{
Ptr2MemPageInfo[i]->Ptr2Page->Back2File();
Ptr2MemPageInfo[i]->bIsModified=0;
}
//放弃内存页的使用
this->Ptr2MemPageInfo[i]->SetFileID(0);
}
}
}
// 设置当前页使之为脏页
void _M_Clock::SetPageModified()
{
this->Ptr2MemPageInfo[this->uiCurrClockPtr]->bIsModified = 1;
}
///////////////////////////////////////////////////////////////////////////////////////
//class _M_PageInfo
//构造函数,初始化成员
_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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -