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

📄 pager_bak.c

📁 sourceforge历史版本完整下载: http://sourceforge.net/project/showfiles.php?group_id=202044 提供了基于b树索引算法的文件数据数据
💻 C
📖 第 1 页 / 共 3 页
字号:
/**
 * @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 + -