📄 buffer.h
字号:
/******************************************************************
** 文件名: Buffer.h
** Copyright (c) 2001-2002 计算机99F MiniSQL开发小组其一
** 创建人: 郭振宇
** 日 期: 2001-11-28
** 修改人: 郭振宇
** 日 期: 2002-01-05
** 描 述: 申明了MiniSQL buffer模块所有类和结构,为保证类
方法私有(未经授权不允访问),多申明为私有,授
权采用申明友元类,友元函数的方法
** 版 本: 1.00
******************************************************************/
#ifndef _BUFFER_H_
#define _BUFFER_H_
//-------------------------------------------------------
extern "C"{
#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
};
//-------------------------------------------------------
#define FILE_PAGESIZE 4096 // 内存页大小
#define MEM_PAGEAMOUNT 1000 // 内存页数量
#ifndef MAX_FILENAME_LEN
#define MAX_FILENAME_LEN 256 // 文件(包含路径)最大长度
#endif
//-------------------------------------------------------
/*********************************************************
* 页头信息,用以标识文件页
**********************************************************/
typedef struct {
unsigned long ulPageID; // 页编号
bool bIsFixed; // 页是否常驻内存
void Initial(unsigned long mypageid,bool myisfixed); // 初始化操作
}_TB_PAGEHEAD;
//-------------------------------------------------------
/*********************************************************
* 文件内地址(相当于内存地址),用以标识数据在文件中
* 的具体存放地址,做为对象可持续化的一个重要一环,通
* 过调用其中的MemAddr()方法可以得到数据在内存中的地址
* 是整个buffer模块成功与其他模块整合的关键
**********************************************************/
class _F_FileAddr{
public:
unsigned long ulFilePageID; // 页编号
unsigned int uiOffset; // 页内偏移量
void Initialize(); // 初始化 (0,0)
//**根据页编号和偏移量,取出当前文件该地址在内存中的地址,同时测试页偏移量是否溢出
void* MemAddr() const;
//**根据页编号和偏移量,取出文件该地址在内存中的地址,同时测试页偏移量是否溢出
void* MemAddr(class _M_File&) const;
//**根据页编号和偏移量,取出文件该地址在内存中的地址,同时测试页偏移量是否溢出
void* MemAddr(class _M_File*) const;
bool operator>=(_F_FileAddr& other) const; // _F_FileAddr >= 操作
bool operator> (_F_FileAddr& other) const; // _F_FileAddr > 操作
bool operator==(_F_FileAddr& other) const; // _F_FileAddr == 操作
bool operator!=(_F_FileAddr& other) const; // _F_FileAddr != 操作
bool operator==(const int zero) const; // _F_FileAddr == 操作
//**在当前页中滑动offset量(可正可负)
void ShiftOffset(int offset);
};
//-------------------------------------------------------
/*********************************************************
* 文件头信息
**********************************************************/
typedef struct{
_F_FileAddr DelFirst; // 第一条被删除记录地址
_F_FileAddr DelLast; // 最后一条被删除记录地址
_F_FileAddr NewInsert; // 文件末尾可插入新数据的地址
unsigned long ulPageTotal; // 目前文件中共有页数
void InitialFileCond(); // 初始化
}_TB_FILECOND;
//-------------------------------------------------------
/*********************************************************
* 内存页,用以从文件中读取页和往文件中写回页
* 同时也提供页头信息等相关信息
**********************************************************/
class _M_Page{
friend class _M_PageInfo;
friend class _F_FileAddr;
friend class _M_Clock;
private:
unsigned int uiFileID; // 所属文件编号(程序动态分配)
unsigned long ulFilePageID; // 在文件中的PageID
void* Ptr2PageBegin; // 调入内存后的页首地址
_TB_PAGEHEAD* Ptr2Head; // 页头信息
_TB_FILECOND* Ptr2FileCond(); // 文件头信息(若页PageID==0,则有,否则返回空)
_M_Page(); // 成员初始化,开辟内存空间
~_M_Page(); // 释放内存空间
//**从文件中调入页至开辟好的内存空间中
void LoadFromFile(unsigned int fileid,unsigned long filepageid);
//**把内存中的页写回到文件中
void Back2File() const;
};
//-------------------------------------------------------
/*********************************************************
* 内存页管理信息,用以管理内存页的开辟,释放等
* 之所以和内存页类分开,为在不必要的情况下可以
* 避免开辟内存页,减少内存的浪费
**********************************************************/
class _M_PageInfo{
friend class _M_Clock;
friend class _F_FileAddr;
friend class _M_Buffer;
private:
bool bIsLastUsed; // 最近一次访问内存是否被使用,用于Clock算法
bool bIsModified; // 从调入内存开始,是否被修改,用于决定是否需要写会文件
class _M_Page* Ptr2Page; // 所分配的内存页对象
_M_PageInfo(); // 成员初始化
~_M_PageInfo(); // 析构,根据bIsModified决定是否需要写会文件
void UpdatePageInfo(unsigned int fileid,unsigned long filepageid); // 页替换、开辟等
_TB_PAGEHEAD* GetPtr2Head() const; // 取得页头信息地址
_TB_FILECOND* GetPtr2FileCond() const; // 取得文件头信息地址
unsigned int GetFileID() const; // 取得所分配的内存页目前内容所属的文件编号
void SetFileID(unsigned int fileid); // 设置新的文件编号(抛弃页时设为0即可)
unsigned long GetFilePageID() const; // 取得所分配的内存页目前内容在文件中的页编号
};
//------------------------------------------------------------
/*********************************************************
* 内存页置换算法实现类,采用Clock算法
* 开辟内存页管理对象数组,每个内存页管
* 理对象对应一个内存页对象,需要的时候
* 才开辟,避免内存的浪费
**********************************************************/
class _M_Clock
{
friend class _M_Buffer;
friend class _M_File;
friend _F_FileAddr MemWrite(const void*,size_t,_F_FileAddr*);
private:
unsigned int uiClockSize; // 内存中页总数,即Clock钟点总数
unsigned int uiCurrClockPtr; // 目前正在使用的内存页
class _M_PageInfo* Ptr2MemPageInfo[MEM_PAGEAMOUNT+1]; // 内存页管理对象(不包含内存页空间)
_M_Clock(); // 成员初始化
~_M_Clock(); // 析构
void SetPageModified(); // 设置当前页使之为脏页
void CloseFilePages(unsigned int fileid); // 关闭文件并抛弃所属内存页(适用于欲删除一个文件的时候)
unsigned int GetNullPage(); // 查找Clock中尚未分配内存空间的页
unsigned int GetFreePage(); // 查找Clock中已经被抛弃的页
unsigned int GetSwapPage(unsigned int fileid); // 查找Clock中最近一页可被替换的页
// 查找Clock中最早打开的文件所占用的内存页,如果是常驻内存页则关闭该文件(该写回的写回)
// 所有打开的文件已经由_M_Buffer类组织成链表
unsigned int NR_Search(unsigned int tarfileid);
// Clock算法实现,通过U_M_Search()四次调用,完成Clock算法
unsigned int U_M_Search(bool islastused,bool ismodified,bool changeused);
// 查找已经存在的页(假设要找的页已经存在的话)
unsigned int GetExsitPage(unsigned int fileid,unsigned long filepageid);
// 根据文件编号和页号取得内存页(通过上面各种方法)
_M_PageInfo* GetTargetPage(unsigned int fileid,unsigned long filepageid);
};
//-------------------------------------------------------
/*********************************************************
* 内存文件类,与其他模块的主要接口,将
* 通过此类得到欲访问文件中的数据的内存首地址
**********************************************************/
class _M_File{
friend class _M_Buffer;
friend class _F_FileAddr;
friend class _M_Clock;
private:
unsigned int uiFileID; // 文件编号
unsigned long ulPageTotal; // 目前文件总的页数
bool IsNew; // 该文件是否新建
char FileName[MAX_FILENAME_LEN]; // 文件名称(包含路径)
_M_File* _F_Next; // 下一个打开的文件
int Ptr2File; // 文件指针
void Deconstruct(); // 析构,关闭文件
_M_PageInfo* GetPageInfo(unsigned long filepageid) const; // 根据页号取得属于该文件的内存页
// 初始化,打开和新建文件,若当前文件开的太多,导致无法再打开新文件,可自动关闭最早打开的文件
_M_File(const char *name,unsigned int fileid);
// 取得相关文件,由于一个表包含两个文件(.idx,.dbf),故查找关联的文件编号
unsigned int GetRelativeFileID() const;
public:
_F_FileAddr GetCataPoint() const; // 取得Catalog模块在文件中可写的第一个位置
_F_FileAddr GetIdxPoint() const; // 取得Catalog模块在文件中可写的第一个位置
_F_FileAddr GetDelListCond() const; // 取得文件内记录删除维护信息
unsigned long GetPageTotal() const; // 取得目前总的页数
// 关闭文件,同时属于该文件的内存页改写回的写回.为保证一致性,同时关闭关联文件
void Close();
};
//-------------------------------------------------------
/*********************************************************
* Buffer模块管理类,包含两部分数据的管理
* 一、内存页的管理,通过一个_M_Clock对象实现
* 二、打开文件的管理,组织所有的文件
**********************************************************/
class _M_Buffer{
friend class _M_Page;
friend class _M_PageInfo;
friend class _M_File;
friend class _M_Clock;
friend class _F_FileAddr;
friend _F_FileAddr MemWrite(const void*,size_t,_F_FileAddr*);
friend _F_FileAddr MemWriteTest(size_t,_F_FileAddr*);
private:
unsigned int uiFileCount; // 打开文件总数
_M_File* _F_First; // 第一个文件
_M_File* _F_Last; // 最后一个文件
_M_File* _F_Current; // 当前使用文件
class _M_Clock* MemPageClock; // Clock算法实现类(管理所有内存页)
_M_File* operator[](unsigned int fileid) const; // 根据文件编号返回内存文件对象
void CloseFile(unsigned int fileid); // 根据文件编号关闭内存文件对象
void CloseTable(unsigned int fileid); // 根据文件编号关闭内存文件对象及其关联内存文件对象
bool GetIsNew(unsigned int fileid) const; // 根据文件编号返回内存文件对象是否为新建
void SetIsNew(unsigned int fileid,bool isnew); // 根据文件编号设置内存文件对象是否为新建
unsigned long GetPageTotal(unsigned int fileid) const; // 根据文件编号返回内存文件对象总页数
void AddPageTotal(unsigned int fileid,int add); // 根据文件编号色设置内存文件对象的总页数
int GetPtr2File(unsigned int fileid) const; // 根据文件编号返回内存文件对象的文件指针
public:
_M_File operator[](const char* filename); // 根据文件名称返回内存文件对象
void Start(); // Buffer初始化
void End(); // Buffer结束,写回内存页,关闭文件
};
//-------------------------------------------------------
/*****************************************************************
** 函数名: MemWrite
** 输 入: const void*,size_t,_F_FileAddr*
** const void* --- 欲写入buffer的对象(数据)的内存地址
** size_t --- 数据总长度
** _F_FileAddr* ---文件内地址,测试判断后,若越界、跨块等情
况下,将自动修正为最终写入文件的地址
** 输 出: _F_FileAddr --- 文件内地址,为下一个文件末尾可写的地址
** 功能描述: 根据欲写入的文件地址,把其他模块内存中的数据写
入buffer中,最终自动写入文件中
** 全局变量: 无
**********************************************************/
_F_FileAddr MemWrite(const void*,size_t,_F_FileAddr*);
//-------------------------------------------------------
/*****************************************************************
** 函数名: MemWriteTest
** 输 入: const void*,size_t,_F_FileAddr*
** const void* --- 欲写入buffer的对象(数据)的内存地址
** size_t --- 数据总长度
** _F_FileAddr* ---文件内地址,测试判断后,若越界、跨块等情
况下,将自动修正为最终写入文件的地址
** 输 出: _F_FileAddr --- 文件内地址,为下一个文件末尾可写的地址
** 功能描述: 根据欲写入的文件地址,测试把其他模块内存中的数据写入
实际未写入。用于当整个数据对象不能跨快写的时候又不能
一次写入(如链表结构(各字段)的一条记录,在内存中不连
续)的场合。
*****************************************************************/
_F_FileAddr MemWriteTest(size_t,_F_FileAddr*);
//-------------------------------------------------------
#endif //define _BUFFER_H_
//-------------------------------------------------------
//-------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -