⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pager.c

📁 sourceforge历史版本完整下载: http://sourceforge.net/project/showfiles.php?group_id=202044 提供了基于b树索引算法的文件数据数据
💻 C
📖 第 1 页 / 共 5 页
字号:
	{		if(0 != pager_open_journal(pager))			return NULL;	}	/* 如果此页已在jf里做备份(pg->page_state != PAGE_CLEAN) */	if(pager_page_is_in_journal(pg))	{		assert(pg->page_num <= pager_get_total_pages_count(pager));		/* 将页置成dirty,并加入dirty list */		if(!pager_page_is_dirty(pg))			pager_make_page_dirty(pager, pg, PAGE_EVT_WRITE_BUF_BK);		return buf_write;	}	/* 如果(pg->page_state == PAGE_CLEAN)将调用以下代码 */	assert(!pager_page_is_dirty(pg));	assert(pager->orig_pages_count != (unsigned int)-1);	if(pg->page_num > pager->orig_pages_count)	{		/*		* 页在修改之前本身是不存在的,所以也不用真正地写入,做个标记即可		* 这里应处理当有多个页的超出页文件大小的情况,因为超出文件大小情况下,只需要同步		* jf头就可以了,这种情况只需要同步一次,即之后再发生这种情况,因为不存在写入的问题		* jf是不用步的,因为已经同步过了		*/		pager_set_total_pages_count(pager, ((unsigned int)pg->page_num));		pager_make_page_dirty(pager, pg, PAGE_EVT_WRITE_BUF_BK);		/* 如果已经做过同步,则需要修改状态 */		if(pager->bsync_journal_has_done)			pager_change_page_state(pg, PAGE_EVT_SYNC_JOURNAL);	}	else	{		unsigned int cksum = pager_cal_page_cksum(pg->pg_buf_start, pager->page_size, pager->cur_cksum_init);		/*		* 如果没有则需要写入jfd, <页缓存内容,先页号,最后写入校验和>,并且给该页缓存做上injournal标识,并在着色表相应的位置置标识		*/		uint_to_big_endian((unsigned int)pg->page_num, (pg->pg_buf_start + pager->page_size), sizeof(unsigned int));		uint_to_big_endian(cksum,			pg->pg_buf_start + pager->page_size + sizeof(unsigned int),			sizeof(unsigned int));		if(0 != OsFileWrite(pager->hjf, pg->pg_buf_start, pager_get_journal_rec_len(pager), NULL))			return NULL;		pager->in_journal_pages_count ++;		pager->journal_end += pager_get_journal_rec_len(pager);		/* 将页置成dirty,并加入dirty list */		pager_make_page_dirty(pager, pg, PAGE_EVT_WRITE_BUF_BK);		assert(!pager_page_is_sync_journal(pg));	}	pager_mark_page_in_journal(pager, pg);	if(!pager_page_is_sync_journal(pg))		pager->need_sync_journal = 1;	return buf_write;}/** * @brief 从jf里回滚 */static __INLINE__ int pager_file_truncate(pager_t * pager, unsigned int page_count){	assert(pager && pager->hf);	if(0 != OsFileTruncate(pager->hf, page_count * pager->page_size))		return -1;	return 0;}/** * @brief 从jf里回滚 */static __INLINE__ int pager_roll_back_one_page(pager_t * pager,											   unsigned int orig_page_count,											   unsigned int cksum_init,											   unsigned char * data_buf,											   const unsigned int data_buf_len){	int ret = 0;	unsigned int cksum = 0;	unsigned int pg_no = 0;	pghd_t * pg = NULL;	assert(pager && pager->hjf && pager->page_size);	assert(pager_get_journal_rec_len(pager) == data_buf_len && data_buf);	assert(pager_get_journal_rec_len(pager) >= pager->page_size);	if(0 != OsFileRead(pager->hjf, data_buf, data_buf_len, NULL))		return RHAPSODY_FAIL;	pager->journal_end += data_buf_len;	/* 计算校验和,判断此页是否是正确的 */	array_to_uint_as_big_endian(data_buf + pager->page_size + sizeof(unsigned int), sizeof(unsigned int), cksum);	if(cksum != pager_cal_page_cksum(data_buf, pager->page_size, cksum_init))		return RHAPSODY_DONE;	/* 在页缓存哈希表里查找 */	array_to_uint_as_big_endian(data_buf + pager->page_size, sizeof(unsigned int), pg_no);	pg = pager_hash_lookup(pager, pg_no);	if(NULL == pg || pager_page_is_written_before_page_sync(pg))	{		/*		* 找不到,需要写回文件		* 找到,则判断是否在提交之前写回过文件,如果有也要写回文件		*/		if(0 != pager_write_page_data(pager, data_buf, pager->page_size, pg_no))			return RHAPSODY_FAIL;	}	/* 重刷内存 */	if(pg)	{		assert(PAGE_CLEAN != pg->pg_state);		memcpy(pg->pg_buf_start, data_buf, pager->page_size);		if(pager_page_is_dirty(pg))		{			assert(pager_page_is_in_dirty_list(pg));			pager_page_out_of_dirty_list(pager, pg);		}		pager_change_page_state(pg, PAGE_EVT_ROLL_BACK);		/* 回调用户的reload回调 */		if(pager->page_reload_cb)			pager->page_reload_cb(pg);	}	return RHAPSODY_OK;}/** * @brief 从jf里回滚 */static __INLINE__ int pager_roll_back_from_journal(pager_t * pager){	int64 file_size = 0;	unsigned int injournal_count = 0;	unsigned int orig_page_count = 0;	unsigned int cksum_init = 0;	int ret = 0;	int bfirst = 1;	int i = 0;	unsigned char * data_buf = NULL;	unsigned int data_buf_len = 0;	assert(pager && pager->hjf);	/* 分配处理回滚过程中需要的内存 */	data_buf_len = pager_get_journal_rec_len(pager);	data_buf = MyMemPoolMalloc(pager->hm, data_buf_len);	if(NULL == data_buf)		return -1;	if(0 != OsFileSize(pager->hjf, &file_size))	{		ret = -1;		goto pager_roll_back_from_journal_end_;	}	if(0 != OsFileSeek(pager->hjf, 0))	{		ret = -1;		goto pager_roll_back_from_journal_end_;	}	pager->journal_end = 0;	while(1)	{		/* 先读取jf头 */		ret = pager_read_jf_head(pager, file_size, &injournal_count, &orig_page_count, &cksum_init);		if(RHAPSODY_OK != ret)			break;		if(bfirst)		{			/* 如果读出的第一个jf头,则要将页文件栽减成原来的大小 */			if(0 != pager_file_truncate(pager, orig_page_count))			{				ret = -1;				goto pager_roll_back_from_journal_end_;			}			pager->total_page_count = orig_page_count;			bfirst = 0;		}		/* 如果是最后一个jf头,并且记录数显示为零,则有可能jf还未同步 */		if(0 == injournal_count && pager->journal_end == (pager->jouranl_prev_hdr + pager->sector_size))		{			/* 说明此时有可能jf本身还同步,剩余的脏页可以直接于页文件里取,因为没有写回 */			assert(pager->journal_end + pager->in_journal_pages_count * pager_get_journal_rec_len(pager) == file_size				|| 0 == pager->ref_count);			assert((pager->journal_end < file_size && pager->need_sync_journal && pager->pg_dirty) || 0 == pager->ref_count || NULL == pager->pg_dirty);			/*			* 此时外存对的页文件的页是干净的,但此时仍然从jf里取			* 代价是额外的计算校验和的开销,			* 如果改成直接从外页页文件中,则看外设的特点,以点os对文件的组织形式.			* 如果外设是flash,此种方法效率较低.			* 如果外设是机械磁盘,则要看页文件的大小,以及os对文件的组织.也许从jf里读,可以减少磁盘io时的寻道时间.			*/			injournal_count = pager->in_journal_pages_count;		}		/* 根据jf头,循环读出每一条备份记录 */		for(i = injournal_count; i > 0; i --)		{			ret = pager_roll_back_one_page(pager, orig_page_count, cksum_init, data_buf, data_buf_len);			if(RHAPSODY_OK != ret)				break;		}	}	{		/*		* 还需要还原内存中那些超过页文件大小的页缓存,		* 将它们的数据刷回0		* todo:优先此段代码		*/		pghd_t * pg = pager->pg_all;		for(; pg; pg = pg->pg_all_next)		{			assert(!pager_page_is_dirty(pg));			if(orig_page_count <= pg->page_num)				memset(pg->pg_buf_start, 0, pager->page_size);			if(pager_page_is_sync_journal(pg) && 0 == pg->ref_count)			{				assert(pager_page_is_in_free_list(pg));				assert(pager_page_is_in_syncjf_list(pg));				pager_out_syncjf_list(pager, pg);			}			assert(!pager_page_is_in_syncjf_list(pg));			if(pager_page_is_dirty(pg))			{				assert(pager_page_is_in_dirty_list(pg));				pager_page_out_of_dirty_list(pager, pg);			}			if(!pager_page_is_clean_not_in_jf(pg))				pager_change_page_state(pg, PAGE_EVT_DEL_JOURNAL);			assert(!pager_page_is_sync_journal(pg));		}		assert(NULL == pager->pg_syncjf_first && NULL == pager->pg_syncjf_last);	}	/* 如果ret != RHAPSODY_FAIL 删除备份日志文件 */	if(RHAPSODY_FAIL != ret)	{		assert(NULL == pager->pg_dirty);		pager->page_file_is_integrity = 1;		if(0 != pager_close_and_del_journal(pager))		{			ret = -1;			goto pager_roll_back_from_journal_end_;		}		ret = 0;	}pager_roll_back_from_journal_end_:	MyMemPoolFree(pager->hm, data_buf);	return ret;}/** * @brief 第一页获取页缓存引用,判断是否存在jf文件,存在则执行回滚操作 */static __INLINE__ int pager_check_and_roll_back(pager_t * pager){	assert(pager && pager->hf);	/* 判断jf文件是否存在,不存在,返回成功 */	if(!OsFileExists((char *)MyBufferGet(pager->hb_jf_name, NULL)))		return 0;	/*	* 存在,需要打开它进行回滚	* 以只读方式打开jf文件	*/	if(0 != pager_open_journal_readonly(pager))		return -1;	/* 回滚 */	if(0 != pager_roll_back_from_journal(pager))		return -1;	return 0;}/** * @brief 重新加载页缓存中的脏页 */static __INLINE__ int pager_reload_cache(pager_t * pager){	unsigned char * buf = NULL;	pghd_t * pg = NULL;	assert(pager && pager->hf);	assert(pager->pg_dirty);	assert(pager->page_size);	assert(pager->page_file_is_integrity);	assert(NULL == pager->pg_syncjf_first && NULL == pager->pg_syncjf_last);	buf = MyMemPoolMalloc(pager->hm, pager->page_size);	if(NULL == buf)		return -1;	for(pg = pager->pg_dirty; pg; pg = pager->pg_dirty)	{		assert(pager_page_is_dirty(pg));		assert(!pager_page_is_in_syncjf_list(pg));		assert(!pager_page_is_sync_journal(pg));		/* 从外存文件读取相应的页 */		if(pg->page_num <= pager->orig_pages_count)		{			if(0 != pager_read_page_data(pager, pg->page_num, buf, pager->page_size))				return -1;			/* 拷贝至页缓存 */			memcpy(pg->pg_buf_start, buf, pager->page_size);		}		else			memset(pg->pg_buf_start, 0, pager->page_size);		/* 改变页的状态 */		pager_page_out_of_dirty_list(pager, pg);		pager_change_page_state(pg, PAGE_EVT_ROLL_BACK);		assert(PAGE_CLEAN == pg->pg_state);		if(pager->page_reload_cb)			pager->page_reload_cb(pg);	}	assert(buf);	MyMemPoolFree(pager->hm, buf);	assert(NULL == pager->pg_dirty);	/* 删除备份的jf文件 */	if(0 != pager_close_and_del_journal(pager))		return -1;	return 0;}/** * @brief 取消所有的页的更改 */static __INLINE__ int pager_rollback(pager_t * pager){	int ret = -1;	assert(pager);	/*	* 在PagerSyn之前,RollBack是有效的,PagerSyn之后,RollBack没有意义了.	* RollBack判断页文件是否已经同步过jfd,并且向fd里写了数据.此时应从jfd里回滚所有页	* 如果没有,则重新加载fd里相应的页至脏页缓存即可,	* 删除份的jfd文件.	* jfd着色表以及页的injournal标识均置成0,因为数据恢复成完整状态.	*/	if(!pager->page_file_is_integrity)/* 如果在提交之前,有部分页缓存有写回至页文件,从jf里还原 */		ret = pager_roll_back_from_journal(pager);	else if(NULL == pager->pg_dirty)/* 如果没有脏的缓存页,把jf删除即可 */		ret = pager_close_and_del_journal(pager);	else/* 如果在提交之前,没有页缓存写回页文件,重新将脏缓存加载一次即可 */		ret = pager_reload_cache(pager);	/* 完成回滚之后,jf应删除 */	return ret;}/** * @brief 按页号递增进行排序的比较回调函数 *  > 0  表示 key1 大于 key2 *  == 0 表示 key1 等于 key2 *  < 0  表示 key1 小于 key2 * * @param context:用户自定义的上下文数据 */static int pager_sort_dirty_compare(const void * data1, const void * data2, const void * context){	pghd_t * pg1 = *((pghd_t **)data1);	pghd_t * pg2 = *((pghd_t **)data2);	assert(pg1 && pg2);	assert(pg2->page_num && pg1->page_num);	/*return pg1->page_num - pg2->page_num */	if(pg1->page_num >= pg2->page_num)		return pg1->page_num - pg2->page_num;	else		return -1;}/** * @brief 同步所有脏缓存页 */static __INLINE__ int pager_sort_dirty_list(pager_t * pager){	/*	* sqlite有用的是归并排序	* 对脏页进行排序,保证从最小的页开始写回外存	* 在将脏页写入外存页文件之前,按页号进行排序是很重要的	*	* 分配一块内存数组	* 将所有的页依次填写这个内存数组	* 以页号为比较关键字对这个数组进行快速排序	* 将排序好的数组按次序添加至dirty list	*/	pghd_t * pg = NULL;	pghd_t ** pg_array = NULL;	unsigned int dirty_pages_count = 0;	unsigned int i = 0;	assert(pager && pager->pg_dirty);	for(pg = pager->pg_dirty; pg; pg = pg->pg_dirty_next)		dirty_pages_count ++;	if(dirty_pages_count <= 1)		return 0;	pg_array = MyMemPoolMalloc(pager->hm, sizeof(pg_array[0]) * dirty_pages_count);	if(NULL == pg_array)		return -1;	for(i = 0, pg = pager->pg_dirty; pg; pg = pg->pg_dirty_next, i ++)	{		assert(pager_page_is_dirty(pg));		assert(pg->page_num);		assert(i < dirty_pages_count);		pg_array[i] = pg;	}	pg = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -