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

📄 pager.c

📁 基于btree索引算法的数据库代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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, &sector_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 + -