📄 pager.c
字号:
pager->total_page_count = (unsigned int)(file_size / pager->page_size);
return pager->total_page_count;
}
/**
* @brief 设置页文件的总页数
*/
#define pager_set_total_pages_count(__pgr, __pgno) do{ \
unsigned int total_pages_count = pager_get_total_pages_count(__pgr);\
assert(__pgno <= total_pages_count + 1);\
if(total_pages_count < __pgno) \
__pgr->total_page_count = __pgno;\
}while(0)
/**
* @brief 获取页缓冲的用户区首地址
*/
#define pager_get_page_bufdata(_pg) ((unsigned char *)(&(_pg[1])))
/**
* @brief 计算指定页号的页首在页文件中的偏移
*/
#define pager_cal_page_hdr_offset(__pgr, __pgno) (__pgr->page_size * (__pgno - 1))
/**
* @brief 根据页号,获取某一页的内容
*/
static __INLINE__ int pager_read_page_data(pager_t * pager, unsigned int pgno, unsigned char * buf, unsigned int buf_len)
{
assert(pager && pgno && buf && pager->page_size && buf_len == pager->page_size);
if(pgno > pager_get_total_pages_count(pager))
{
memset(buf, 0, pager->page_size);
return 0;
}
if(0 != OsFileSeek(pager->hf, pager_cal_page_hdr_offset(pager, pgno)))
return -1;
if(0 != OsFileRead(pager->hf, buf, pager->page_size, NULL))
return -1;
return 0;
}
/**
* @brief 根据页号,获取一页至缓存
*/
static __INLINE__ int pager_read_page(pager_t * pager, unsigned int pgno, pghd_t * pg)
{
assert(pager && pgno && pg && pg->pager == pager);
assert(pager->hf);
if(0 != pager_read_page_data(pager, pgno, pg->pg_buf_start, pager->page_size))
return -1;
return 0;
}
/**
* @brief 将指定的数据写进某一页
*/
static __INLINE__ int pager_write_page_data(pager_t * pager, unsigned char * buf, unsigned int buf_size, unsigned int pgno)
{
assert(pager && buf && buf_size);
assert(pager->hf);
assert(buf_size <= pager->page_size);
/* 将页写入外存页文件 */
if(0 != OsFileSeek(pager->hf, pager_cal_page_hdr_offset(pager, pgno)))
return -1;
if(0 != OsFileWrite(pager->hf, buf, buf_size, NULL))
return -1;
return 0;
}
/**
* @brief 将某一个数据写入页文件
*/
static __INLINE__ int pager_write_page(pager_t * pager, pghd_t * pg)
{
assert(pager && pg && pager == pg->pager);
assert(pg->page_num);
assert(pager->hf);
assert(pager_page_is_dirty(pg));
/* 将页写入外存页文件 */
if(0 != pager_write_page_data(pager, pg->pg_buf_start, pager->page_size, pg->page_num))
return -1;
return 0;
}
/**
* @brief 寻找jf头的位置
* jf头的位置应对齐到sector_size的值,假如sector_size为512
* 0 512 1024为jf头的起始位置
*/
#define pager_locate_jf_hdr_pos(__pgr) \
((__pgr->journal_end % __pgr->sector_size)?(__pgr->journal_end + CAL_ALIGMENT(__pgr->journal_end, __pgr->sector_size)):__pgr->journal_end)
/**
* @brief 写jf头
*/
static __INLINE__ int pager_reset_cksum(pager_t * pager)
{
assert(pager && pager->hrand);
pager->cur_cksum_init = (unsigned int)(myrandGetByte(pager->hrand)) << 24 |
(unsigned int)(myrandGetByte(pager->hrand)) << 16 |
(unsigned int)(myrandGetByte(pager->hrand)) << 8 |
(unsigned int)(myrandGetByte(pager->hrand));
return 0;
}
/**
* @brief 写jf头
*/
static __INLINE__ int pager_write_jf_head(pager_t * pager)
{
int ret = -1;
unused_journal_hdr * hdr = MyMemPoolMalloc(pager->hm, pager->sector_size);
if(NULL == hdr)
goto pager_write_jf_head_end_;
memset(hdr, 0, pager->sector_size);
assert(pager && pager->hjf && pager->hrand && pager->sector_size >= sizeof(*hdr));
/*
* journal日志文件头定义
* offset bytes des
* 0 4 头的大小hd_sz
* 4 16 格式版本
* 20 4 日志里备份了几页
* 24 4 校验和初始随机值
* 28 4 备份日志前页文件的大小
* 32 hd_sz-24 保留
*/
pager->jouranl_prev_hdr = pager_locate_jf_hdr_pos(pager);
assert((pager->jouranl_prev_hdr % pager->sector_size) == 0);
assert(pager->jouranl_prev_hdr >= pager->journal_end);
if(0 != OsFileSeek(pager->hjf, pager->jouranl_prev_hdr))
goto pager_write_jf_head_end_;
/* 写入头的大小 */
uint_to_big_endian(pager->sector_size, hdr->sector_size, sizeof(hdr->sector_size));
/* 拷贝魔法数 */
memcpy(hdr->magic, JOURNAL_MAGIC_STRING, sizeof(hdr->magic));
/* 写记录数,初始应为零 */
uint_to_big_endian(0, hdr->rec_count, sizeof(hdr->rec_count));
/* 写入校验和初始随机值 */
pager_reset_cksum(pager);
uint_to_big_endian(pager->cur_cksum_init, hdr->cksum_init, sizeof(hdr->cksum_init));
/* 写入备份jf前页文件有多少页,用于回滚时栽减 */
uint_to_big_endian(pager->total_page_count, hdr->orig_page_count, sizeof(hdr->orig_page_count));
if(0 != OsFileWrite(pager->hjf, hdr, pager->sector_size, NULL))
goto pager_write_jf_head_end_;
pager->journal_end = pager->jouranl_prev_hdr + pager->sector_size;
ret = 0;
pager_write_jf_head_end_:
if(hdr)
MyMemPoolFree(pager->hm, hdr);
return ret;
}
/**
* @brief 读jf头
* @return 0:成功 -1:失败 1:内容不正确,但是操作应结束了
*/
static __INLINE__ int pager_read_jf_head(pager_t * pager,
int64 file_size,
unsigned int * pin_journal_count,
unsigned int * porig_pages_count,
unsigned int * pcksum_init)
{
unsigned int sector_size = 0;
char magic[JOURNAL_MAGIC_LEN];
assert(pager && pager->hjf && pin_journal_count && porig_pages_count);
/*
* journal日志文件头定义
* offset bytes des
* 0 4 头的大小hd_sz
* 4 16 格式版本
* 20 4 日志里备份了几页
* 24 4 校验和初始随机值
* 28 4 备份日志前页文件的大小
* 32 hd_sz-24 保留
*/
/* 定位jf头的偏移 */
pager->journal_end = pager_locate_jf_hdr_pos(pager);
if(pager->journal_end + PAGER_JOURNAL_REC_COUNT_LEN >= file_size)
return RHAPSODY_DONE;
if(OsFileSeek(pager->hjf, pager->journal_end))
return RHAPSODY_FAIL;
/* 读出页头的大小 */
if(0 != pager_read_uint_from_file(pager->hjf, §or_size))
return RHAPSODY_FAIL;
if(sector_size < PAGER_MIN_SECTOR_SIZE)
return RHAPSODY_DONE;
if(pager->journal_end + PAGER_JOURNAL_REC_COUNT_LEN >= file_size)
return RHAPSODY_DONE;
/* 读出magic字符串,判断它是否合法 */
if(0 != OsFileRead(pager->hjf, magic, sizeof(magic), NULL))
return RHAPSODY_FAIL;
if(memcmp(magic, JOURNAL_MAGIC_STRING, JOURNAL_MAGIC_LEN) != 0)
return RHAPSODY_DONE;
/* 读出日志里备份了几页 */
if(0 != pager_read_uint_from_file(pager->hjf, pin_journal_count))
return RHAPSODY_FAIL;
/* 读出校验和初始值 */
if(0 != pager_read_uint_from_file(pager->hjf, pcksum_init))
return RHAPSODY_FAIL;
/* 读出备份前的页文件大小 */
if(0 != pager_read_uint_from_file(pager->hjf, porig_pages_count))
return RHAPSODY_FAIL;
pager->journal_end += sector_size;
/* 定位文件指针位置 */
if(0 != OsFileSeek(pager->hjf, pager->journal_end))
return RHAPSODY_FAIL;
return RHAPSODY_OK;
}
/**
* @brief 以只读的方式打开journal
*/
static __INLINE__ int pager_open_journal_readonly(pager_t * pager)
{
assert(pager && NULL == pager->hjf);
/* 打开jf文件 */
pager->hjf = OsFileOpenReadOnly((char *)MyBufferGet(pager->hb_jf_name, NULL), pager->hm);
if(NULL == pager->hjf)
return -1;
/* 清空原有的着色表 */
assert(pager->hash_pgno_journal);
MyHashTableClear(pager->hash_pgno_journal);
pager->pg_syncjf_first = NULL;
pager->pg_syncjf_last = NULL;
pager->in_journal_pages_count = 0;
pager->orig_pages_count = pager_get_total_pages_count(pager);
pager->need_sync_journal = 0;
pager->bsync_journal_has_done = 0;
pager->jouranl_prev_hdr = 0;
pager->journal_end = 0;
return 0;
}
/**
* @brief 打开jf
*/
static __INLINE__ int pager_open_journal(pager_t * pager)
{
assert(pager && NULL == pager->hjf);
/* 打开jf文件 */
pager->hjf = OsFileOpenExclusive((char *)MyBufferGet(pager->hb_jf_name, NULL), pager->hm);
if(NULL == pager->hjf)
return -1;
pager->jouranl_prev_hdr = 0;
pager->journal_end = 0;
/* 写入jf头,校验和初始化随机数值,初始数据库的大小 */
if(0 != pager_write_jf_head(pager))
return -1;
/* 清空原有的着色表 */
assert(pager->hash_pgno_journal);
MyHashTableClear(pager->hash_pgno_journal);
pager->pg_syncjf_first = NULL;
pager->pg_syncjf_last = NULL;
pager->in_journal_pages_count = 0;
pager->orig_pages_count = pager_get_total_pages_count(pager);
pager->need_sync_journal = 0;
pager->bsync_journal_has_done = 0;
return 0;
}
/**
* @brief 关闭jf并删除jf文件,清空所有跟jf有关的
*/
static __INLINE__ int pager_close_and_del_journal(pager_t * pager)
{
assert(pager && pager->hjf);
if(0 != OsFileClose(pager->hjf))
return -1;
pager->hjf = NULL;
if(0 != OsFileDel(MyBufferGet(pager->hb_jf_name, NULL)))
return -1;
assert(pager->hash_pgno_journal);
MyHashTableClear(pager->hash_pgno_journal);
assert(NULL == pager->pg_syncjf_first && NULL == pager->pg_syncjf_last);
pager->in_journal_pages_count = 0;
pager->orig_pages_count = (unsigned int)-1;
pager->need_sync_journal = 0;
pager->bsync_journal_has_done = 0;
pager->jouranl_prev_hdr = 0;
pager->journal_end = 0;
return 0;
}
/**
* @brief 计算一页数的校验和
*/
static __INLINE__ unsigned int pager_cal_page_cksum(unsigned char * pg_data, unsigned int pg_sz, unsigned int ckcsum_init)
{
unsigned int i = pg_sz - 1;
assert(pg_data && pg_sz);
for(; i; i /= 2)
ckcsum_init += *((unsigned char *)pg_data + i);
return ckcsum_init;
}
/**
* @brief 标记一页要jf里s
*/
static __INLINE__ unsigned int pager_mark_page_in_journal(pager_t * pager, pghd_t * pg)
{
assert(pager && pg && pager == pg->pager);
assert(pg->page_num);
if(NULL == MyHashTableInsertUnique(pager->hash_pgno_journal, (void *)pg->page_num, NULL))
return -1;
return 0;
}
/**
* @brief 回收一页缓存
*/
static __INLINE__ pghd_t * pager_recycle_page(pager_t * pager)
{
int need_sync = 0;
pghd_t * pg = NULL;
assert(pager);
assert(pager->pg_free_first);
/*
* 如果存在引用计数为零的页缓存,则淘汰该页缓存,用于装载新的页,此时需要将此页写回fd,
* 优先取那些同步过jfd的空闲页缓存,如果没有,则同步jfd,同时从哈希表里删除相应的记录
* 如果页处在空闲链表中,脱链
* 如果页处在同步过jfd的空闲链表中,脱链
*/
if(pager->pg_syncjf_first)
{
/* 优先取同步过jfd的空闲缓存页 */
pg = pager->pg_syncjf_first;
need_sync = 0;
}
else
{
/* 如果没有,则取没同步过的空闲页缓存 */
pg = pager->pg_free_first;
need_sync = 1;
}
assert(pg);
if(pager_page_is_dirty(pg))
{
if(need_sync)
{
/* 同步jf */
if(0 != pager_sync_journal(pager))
return NULL;
pager->in_journal_pages_count = 0;
if(0 != pager_write_jf_head(pager))
return NULL;
}
/* 写回fd */
if(0 != pager_write_page(pager, pg))
return NULL;
/* 应记录已经有页缓存写入了页文件,但数据还不是完整的 */
pager->page_file_is_integrity = 0;
/* 将页置成干净,并从dirty链表中脱链 */
pager_page_out_of_dirty_list(pager, pg);
/* 将页的状态置成写回状态 */
pager_change_page_state(pg, PAGE_EVT_WRITE_BACK_SYNCJF);
}
else
assert(pager_page_is_clean_not_in_jf(pg) || (pager_page_in_journal(pager, pg->page_num) && pager_page_is_sync_journal(pg)));
/* 如果在空闲链表中则脱链 */
pager_out_free_list(pager, pg);
assert(!pager_page_is_in_free_list(pg));
assert(!pager_page_is_in_syncjf_list(pg));
/* 从哈希表中删除,并从记录所有页缓存的链表中删除 */
pager_outof_page_from_hash_and_list(pager, pg);
return pg;
}
/**
* @brief 回收一页缓存,并初始化
*/
static __INLINE__ pghd_t * pager_recycle_and_init_page(pager_t * pager, unsigned int pgno)
{
pghd_t * pg = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -