📄 pager.c
字号:
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; assert(pager && pgno); pg = pager_recycle_page(pager); if(NULL == pg) return NULL; assert(NULL == pg->pg_all_next && NULL == pg->pg_all_prev && !pager_page_is_in_free_list(pg) && !pager_page_is_in_syncjf_list(pg) && !pager_page_is_in_dirty_list(pg) && !pager_page_is_dirty(pg)); pager_init_page(pager, pg, pgno); return pg;}/** * @brief 将某一个页缓存置成脏,并写入jf */static __INLINE__ void * pager_make_page_writable(pghd_t * pg){ pager_t * pager = NULL; void * buf_write = NULL; /* * 判断jfd机制是否已启用,如果未启用则应该打开jfd文件,并分配着色表 * 判断此页是否已经处在jfd中了(从着色表里查), * 如果没有则需要写入jfd,先页号,再写页缓存内容,最后写入校验和,并且给该页缓存做上injournal标识,并在着色表相应的位置置标识 * 将页缓存置成dirty,加入dirty链表. * 如果页号比当前总页数大, * 此时应将页文件的总页数增1 * 返回页缓存的首地址供上层写入(注意越界检测代码加入) */ assert(pg && pg->pager); assert(pg->ref_count > 0); buf_write = pager_get_page_bufdata(pg); pager = pg->pager; /* 如果未启用jf机制,则应启用 */ if(NULL == pager->hjf)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -