} #endif {
/* Write the nRec value into the journal file header. If in
** full-synchronous mode, sync the journal first. This ensures that ** all data has really hit the disk before nRec is updated to mark ** it as a candidate for rollback. */
if( pPager->fullSync ){
TRACE2(\
//首先保证脏页面中所有的数据都已经写入日志文件 rc = sqlite3OsSync(pPager->jfd, 0); if( rc!=0 ) return rc; }
rc = sqlite3OsSeek(pPager->jfd,
pPager->journalHdr + sizeof(aJournalMagic)); if( rc ) return rc;
//页面的数目写入日志文件
rc = write32bits(pPager->jfd, pPager->nRec); if( rc ) return rc;
rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); if( rc ) return rc; }
TRACE2(\ rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync); if( rc!=0 ) return rc;
pPager->journalStarted = 1; }
pPager->needSync = 0;
/* Erase the needSync flag from every page. */
//清除needSync标志位
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->needSync = 0; }
pPager->pFirstSynced = pPager->pFirst; }
#ifndef NDEBUG
/* If the Pager.needSync flag is clear then the PgHdr.needSync ** flag must also be clear for all pages. Verify that this ** invariant is true.
*/ else{
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); }
assert( pPager->pFirstSynced==pPager->pFirst ); } #endif
return rc; }
4.8、获取排斥锁(Obtaining An Exclusive Lock)
在对数据库文件进行修改之前(注:这里不是内存中的页面),我们必须得到数据库文件的排斥锁(Exclusive Lock)。得到排斥锁的过程可分为两步:首先得到Pending lock;然后Pending lock升级到exclusive lock。
Pending lock允许其它已经存在的Shared lock继续读数据库文件,但是不允许产生新的shared lock,这样做目的是为了防止写操作发生饿死情况。一旦所有的shared lock完成操作,则pending lock升级到exclusive lock。
4.9、修改的页面写入文件(Writing Changes To The Database File)
一旦得到exclusive lock,其它的进程就不能进行读操作,此时就可以把修改的页面写回数据库文件,但是通常OS都把结果暂时保存到磁盘缓存中,直到某个时刻才会真正把结果写入磁盘。
以上两步的实现代码:
//把所有的脏页面写入数据库
//到这里开始获取EXCLUSIVEQ锁,并将页面写回操作系统文件 static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; int rc;
if( pList==0 ) return SQLITE_OK; pPager = pList->pPager;
/* At this point there may be either a RESERVED or EXCLUSIVE lock on the ** database file. If there is already an EXCLUSIVE lock, the following ** calls to sqlite3OsLock() are no-ops. **
** Moving the lock from RESERVED to EXCLUSIVE actually involves going
** through an intermediate state PENDING. A PENDING lock prevents new ** readers from attaching to the database but is unsufficient for us to ** write. The idea of a PENDING lock is to prevent new readers from
** coming in while we wait for existing readers to clear. **
** While the pager is in the RESERVED state, the original database file ** is unchanged and we can rollback without having to playback the ** journal into the original database file. Once we transition to
** EXCLUSIVE, it means the database file has been changed and any rollback ** will require a journal playback. */
//加EXCLUSIVE_LOCK锁
rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; }
while( pList ){
assert( pList->dirty );
rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); if( rc ) return rc;
/* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3pager_truncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */
if( pList->pgno<=pPager->dbSize ){
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE3(\ //写入文件
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize); TEST_INCR(pPager->nWrite); }
#ifndef NDEBUG else{
TRACE3(\ } #endif
if( rc ) return rc; //设置dirty pList->dirty = 0;
#ifdef SQLITE_CHECK_PAGES
pList->pageHash = pager_pagehash(pList); #endif
//指向下一个脏页面 pList = pList->pDirty; }
return SQLITE_OK; }
4.10、修改结果刷入存储设备(Flushing Changes To Mass Storage)
为了保证修改结果真正写入磁盘,这一步必不要少。对于数据库存的完整性,这一步也是关键的一步。由于要进行实际的I/O操作,所以和第7步一样,将花费较多的时间。
最后来看看这几步是如何实现的:
其实以上以上几步是在函数sqlite3BtreeSync()---btree.c中调用的(而关于该函数的调用后面再讲)。
代码如下: Code
//同步btree对应的数据库文件
//该函数返回之后,只需要提交写事务,删除日志文件 int sqlite3BtreeSync(Btree *p, const char *zMaster){ int rc = SQLITE_OK;
if( p->inTrans==TRANS_WRITE ){ BtShared *pBt = p->pBt;
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库SQLite入门与分析(8)在线全文阅读。
相关推荐: