📄 pager_bak.c
字号:
/**
* @file page.c page cache management 2008-1-29 23:59
*
* @author lin shao chuan (email:lsccsl@tom.com, msn:lsccsl@163.net)
*
* @brief if it works, it was written by lin shao chuan, if not, i don't know who wrote it.
* descride the detail of the page cache management
* 负责缓存page管理,page内存池管理, 外存空闲页管理,以及外存空闲页整理(通过heap管理空闲页表)
*
* 外存文件格式
* 第一页
* 前128字节:
* offset bytes des
* 0 16 格式版本
* 16 2 页大小
* 18
*
* 验证:os是否是按块写文件,sync时是否安脏块同步
*
* * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. lin shao chuan makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * see the GNU General Public License for more detail. */
#include "pager.h"
#include "mybuffer.h"
#include "myhashtable.h"
#include "mybitvector.h"
#include "OsFile.h"
#define JOURNAL "-journal"
#define VERSION "Rhapsody V0.1.7\000"
#define MIN_PAGE_SIZE 256
#define MAX_PAGE_SIZE 32768
#define DEFAULT_CACHE_PAGES_COUNT 8
#define BYTE_RESERVE_PER_PAGE 4
typedef struct __pager_t_
{
/* 内存池句柄 */
HMYMEMPOOL hm;
/* 辅存文件名 */
HMYBUFFER hb_file_name;
/* 辅存的页文件句柄 */
HOSFILE hf;
/* journal文件名 */
HMYBUFFER hb_jf_name;
/* journal 文件句柄 */
HOSFILE hjf;
/* 记录空闲页链表,回收此链表里的页时,首先同步jfd,以保证数据的完整性 */
struct __pghd_t_ * pg_free_first, pg_free_last;
/*
* 记录已经同步过jf的空闲页链表,回收时,优先回收这个链表里的页
* 当获取空头页缓存时,如果该页处在这个链表里头,则应从链表里头将此页脱链
*/
struct __pghd_t_ * pg_syncjf_first, pg_syncjf_last;
/* 是否已经做了jfd同步的操作,重置时需要此标识置成0 */
int bsync_journal;
/* 记录有多少页进入jfd备份,并且尚未同步外存 */
size_t in_journal_pages_count;
/* 记录页是否处journal状态的位着色表 */
HMYBITVECTOR bitvector_journal;
/* 记录所有的页 */
struct __pghd_t_ * pg_all;
/* 记录脏页,同步时,将这些页先同步至jfd,然后写入fd并同步 */
struct __pghd_t_ * pg_dirty;
/* 文件页号与页面缓存的哈希映射表 <pgno> - <pghd_t *> */
HMYHASHTABLE hash_page;
/* 记录外存文件有多少页 */
size_t total_page_count;
/* 缓存中的最大页数 */
size_t max_cache_pages;
/*
* 当前已缓存页数总量
* 于解除对页的引用时,当cached_page_count大于max_cache_pages,并且该页的引用计数为零
* 则应释放该一页空闲页缓存(有可能就是当前在释放的那一页缓存)
*/
size_t cached_page_count;
/* 每页大小 */
size_t page_size;
/* 外存最低使用率,低于最低使用率是,将进行栽减 */
int used_rate;
/* 每页附加的用户扩展数据大小 */
size_t extra_size;
/* 页的加载与取消引用以及移动时的回调函数 */
PAGE_RELEASE page_release_cb;
PAGE_RELOAD page_reload_cb;
PAGE_MOVE page_move_cb;
}pager_t;
typedef struct __pghd_t_
{
/* which pager this page belong to */
pager_t * pager;
/* 页号 */
size_t page_num;
/* 页缓存引用记数 */
size_t ref_count;
/* 该页是否为脏 0:否 1:为脏,做为同步时是否需要写入外存的依据 */
int dirty;
/* 是否已经在jfd里做了备份 */
int bin_journal;
/* 是否已在同步至jfd */
int bsync_journal;
/* 前一个与后一个空闲页,当页的引用计数为0时,应加入这个链表 */
struct __pghd_t_ * pg_free_prev, pg_free_next;
/*
* 记录已经同步过jf的空闲页链表,回收时,优先回收这个链表里的页
* 当获取空头页缓存时,如果该页处在这个链表里头,则应从链表里头将此页脱链
* 当页的引用计数为零时,并且已经同步了hjf,应加入此链表
*/
struct __pghd_t_ * pg_syncjf_prev, pg_syncjf_next;
/* 后一个脏页,构成一个脏页缓冲链表 */
struct __pghd_t_ * pg_dirty_next;
/* 后一个页,构成一个所有页的链表 */
struct __pghd_t_ * pg_all_next;
/*
* 用于页管理而预留的一些字节
* 第一个字节表示该页是否为空闲页
*/
union pg_manage_area
{
struct __pg_manage_area
{
/* 第一个字节表示该页是否为空闲页 */
char used;
/* 保留字节,暂时没有意义 */
char x1;
char x2;
char x3;
}pgrm;
unsigned char pg_buf_start[BYTE_RESERVE_PER_PAGE];
}pgrm;
}pghd_t;
/**
* @brief 获取页缓存区
*/
#define pager_get_page_bufdata(page) ((void *)(&(page[1])))
/**
* @brief 获取外存文件包含有多少页
*/
static __INLINE__ size_t pager_get_pages_count(pager_t * pager)
{
int64 file_size = 0;
assert(pager && pager->hf);
if(pager->page_count != (size_t)-1)
return pager->page_count;
if(0 != OsFileSize(pager->hf, &file_size))
return -1;
pager->page_count = file_size / pager->page_size;
return pager->page_count;
}
/**
* @brief 获取已经缓存了多少页
*/
static __INLINE__ size_t pager_get_cache_page_count(pager_t * pager)
{
assert(pager && pager->hash_page);
return MyHashTableGetElementCount(pager->hash_page);
}
/**
* @brief 从外存读取一页至缓存
*/
static __INLINE__ int pager_read_page(pager_t * pager, pghd_t * pg, size_t pgno)
{
assert(pager && pg);
pg->page_num = pgno;
if(!OsFileSeek(pager->hf, (pgno - 1) * pager->page_size))
return -1;
if(0 == OsFileRead(pager->hf, pg->page_buf, pager->page_size, NULL))
return 0;
return -1;
}
/**
* @brief 分配一页
*/
static __INLINE__ pghd_t * pager_allocate_page(pager_t * pager)
{
/* 页头信息存储空间 + 页缓存空间 + 用户数据空间 + 页号与校验和存储空间 */
return (pghd_t *)MyMemPoolMalloc(pager->hm, sizeof(*pg) + pager->page_size + pager->extra_size +
sizeof(size_t) + sizeof(unsigned int));
}
/**
* @brief 从空闲链表中脱链
*/
static __INLINE__ int pager_out_free_list(pager_t * pager, pghd_t * pg)
{
assert(pager && pg && pager->page_free && 0 == pg->ref_count);
assert(pg->pager == pager);
/* 如果引用计数为零,必在链表中,要么为链表头,要么中间节点 */
assert(pg->pfree_next || pg->pfree_prev || pg == pager->page_free);
if(pg->pfree_prev)
pg->pfree_prev->pfree_next = pg->pfree_next;
if(pg->pfree_next)
pg->pfree_next->pfree_prev = pg->pfree_prev;
if(pg == pager->page_free)
pager->page_free = pg->pfree_next;
return 0;
}
/**
* @brief 增加指定页的引用计数
*/
static __INLINE__ int page_ref(pager_t * pager, pghd_t * pg)
{
assert(pager && pg);
assert(pg->pager == pager);
/* 如果引用计数零,则从空闲链表中除去,引用计数加1 */
if(0 == pg->ref_count)
pager_out_free_list(pager, pg);
assert(pager->page_free);
pg->ref_count ++;
return 0;
}
/**
* @brief 呼叫页释放时的回调函数
*/
static __INLINE__ int pager_page_release(pager_t * pager, pghd_t * pg)
{
assert(pager && pg);
if(pager->page_release_cb)
return pager->page_release_cb(pager_get_page_bufdata(pg), pager->page_size);
return 0;
}
/**
* @brief 回收一页
*/
static __INLINE__ int pager_recycle(pager_t * pager, pghd_t ** ppg)
{
assert(pager && ppg);
/*
* 回收一页缓存
* 首先需要将要回收的页缓存中的内容写回外存
* 通知已引用此页的用户放弃对本页的引用,并且析构此页的用户数据
* 如果没有用户引用此页,则不必做些回调通知
*/
if(pager->page_free)
{
/* 是否有可以回收的页(引用计数为零的页) */
*ppg = pager->page_free;
/* 页引用计数增1,并根据需要从空闲链表中脱链 */
page_ref(pager, *ppg);
return 0;
}
//如果可用的缓存没有空闲页,则强行回收一页,并要调用用户的析构函数进行通知
//强行回收需要将日志页写入,并将
??????????????
}
/**
* @brief 在哈希表中查找缓存中的页
*/
static pghd_t * page_hash_lookup(pager_t * pager, size_t pgno)
{
HMYHASHTABLE_ITER it = NULL;
assert(pager && pager->hash_page);
it = MyHashTableSearch(pager->hash_page, (void *)pgno);
if(NULL == it)
return NULL;
assert(MyHashTableGetIterData(it));
assert(((pghd_t *)MyHashTableGetIterData(it))->pager == pager);
return (pghd_t *)MyHashTableGetIterData(it);
}
/**
* @brief 将脏缓存页写入页文件
*/
static int write_dirty_to_page_file(pager_t * pager)
{
pghd_t * page = NULL;
assert(pager);
if(NULL == pager->page_dirty)
return 0;
page = pager->page_dirty;
for(; page; page = pager->page_dirty);
{
assert(???????);
}
}
/**
* @brief 销毁缓存管理
*/
static int pager_destroy(pager_t * pager)
{
assert(pager);
if(pager->hf)
OsFileClose(pager->hf);
if(pager->hjf)
OsFileClose(pager->hjf);
MyMemPoolFree(pager);
assert(0);
return -1;
}
/**
* @brief 将备份的页缓存同步至日志里,在往hf里写入更改前,调用此函数,确保断点回滚,保证页文件数据的完整性
*/
static int pager_sync_journal(pager_t * pager)
{
/* 如果hjf未被打开, 说明一定不存在脏页 */
assert(NULL == pager->hjf && NULL == pager->pg_dirty);
/*先同步hjf*/
if(hpgr->hjf)
if(0 != OsFileSyn(hpgr->hjf))
return -1;
/* 所有脏页打上已经同步了hjf的标志 */
///* 该页是否为脏 0:否 1:为脏,做为同步时是否需要写入外存的依据 */
//int dirty;
///* 是否已经在jfd里做了备份 */
//int bin_journal;
///* 是否已在同步至jfd */
//int bsync_journal;
return 0;
}
/**
* @brief 读取页文件信息,读取页大小,以及包含多少页,并判断文件版本
*/
static int pager_read_file_page_info(pager_t * pager)
{
/*
* 页的第一页用于存放页文件本身的信息,<页格式版本号,页大小,第一个空闲页> <用户数据>
*/
char ver[sizeof(VERSION)];
char pg_size[sizeof(unsigned int)];
assert(pager && pager->hf);
OsFileSeek(pager->hf, 0);
if(OsFileRead(pager->hf, ver, sizeof(ver), NULL))
return 0;
if(strncmp(ver, VERSION, strlen(VERSION)) != 0)
{
LOG_WARN(("page file version err,this page maybe create by the later pager verion,[file version:%s], [program ver:%s]",
ver, VERSION));
return -1;
}
OsFileSeek(pager->hf, sizeof(VERSION));
if(OsFileRead(pager->hf, pg_size, sizeof(pg_size), NULL))
return 0;
array_to_uint_as_big_endian(pg_size, sizeof(pg_size), pager->page_size);
pager->total_page_count = pager_get_pages_count(pager);
}
/**
* @brief 页缓存哈希表哈希函数
*/
static size_t pg_hash_fun(const void * key)
{
return (size_t)key;
}
/**
* @brief 页缓存哈希表,比较键值是否相等 1:相等 0:不相等
*/
typedef int pg_hash_keyequl_fun(const void * key1, const void * key2)
{
return key1 == key2;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -