您的位置:首页 > 数据库

SQLite入门与分析(四)---Page Cache之事务处理(2)

2009-02-26 14:16 381 查看
写在前面:个人认为pager层是SQLite实现最为核心的模块,它具有四大功能:I/O,页面缓存,并发控制和日志恢复。而这些功能不仅是上层Btree的基础,而且对系统的性能和健壮性有关至关重要的影响。其中并发控制和日志恢复是事务处理实现的基础。SQLite并发控制的机制非常简单——封锁机制;别外,它的查询优化机制也非常简单——基于索引。这一切使得整个SQLite的实现变得简单,SQLite变得很小,运行速度也非常快,所以,特别适合嵌入式设备。好了,接下来讨论事务的剩余部分。

6、修改位于用户进程空间的页面(Changing Database Pages In User Space)

页面的原始数据写入日志之后,就可以修改页面了——位于用户进程空间。每个数据库连接都有自己私有的空间,所以页面的变化只对该连接可见,而对其它连接的数据仍然是磁盘缓存中的数据。从这里可以明白一件事:一个进程在修改页面数据的同时,其它进程可以继续进行读操作。图中的红色表示修改的页面。

Code

//同步btree对应的数据库文件

//该函数返回之后,只需要提交写事务,删除日志文件

int sqlite3BtreeSync(Btree *p, const char *zMaster){

int rc = SQLITE_OK;

if( p->inTrans==TRANS_WRITE ){

BtShared *pBt = p->pBt;

Pgno nTrunc = 0;

#ifndef SQLITE_OMIT_AUTOVACUUM

if( pBt->autoVacuum ){

rc = autoVacuumCommit(pBt, &nTrunc);

if( rc!=SQLITE_OK ){

return rc;

}

}

#endif

//调用pager进行sync

rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);

}

return rc;

}

//把pager所有脏页面写回文件

int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){

int rc = SQLITE_OK;

TRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",

pPager->zFilename, zMaster, nTrunc);

/* If this is an in-memory db, or no pages have been written to, or this

** function has already been called, it is a no-op.

*/

//pager不处于PAGER_SYNCED状态,dirtyCache为1,

//则进行sync操作

if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){

PgHdr *pPg;

assert( pPager->journalOpen );

/* If a master journal file name has already been written to the

** journal file, then no sync is required. This happens when it is

** written, then the process fails to upgrade from a RESERVED to an

** EXCLUSIVE lock. The next time the process tries to commit the

** transaction the m-j name will have already been written.

*/

if( !pPager->setMaster ){

//pager修改计数

rc = pager_incr_changecounter(pPager);

if( rc!=SQLITE_OK ) goto sync_exit;

#ifndef SQLITE_OMIT_AUTOVACUUM

if( nTrunc!=0 ){

/* If this transaction has made the database smaller, then all pages

** being discarded by the truncation must be written to the journal

** file.

*/

Pgno i;

void *pPage;

int iSkip = PAGER_MJ_PGNO(pPager);

for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){

if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){

rc = sqlite3pager_get(pPager, i, &pPage);

if( rc!=SQLITE_OK ) goto sync_exit;

rc = sqlite3pager_write(pPage);

sqlite3pager_unref(pPage);

if( rc!=SQLITE_OK ) goto sync_exit;

}

}

}

#endif

rc = writeMasterJournal(pPager, zMaster);

if( rc!=SQLITE_OK ) goto sync_exit;

//sync日志文件

rc = syncJournal(pPager);

if( rc!=SQLITE_OK ) goto sync_exit;

}

#ifndef SQLITE_OMIT_AUTOVACUUM

if( nTrunc!=0 ){

rc = sqlite3pager_truncate(pPager, nTrunc);

if( rc!=SQLITE_OK ) goto sync_exit;

}

#endif

/* Write all dirty pages to the database file */

pPg = pager_get_all_dirty_pages(pPager);

//把所有脏页面写回操作系统文件

rc = pager_write_pagelist(pPg);

if( rc!=SQLITE_OK ) goto sync_exit;

/* Sync the database file. */

//sync数据库文件

if( !pPager->noSync ){

rc = sqlite3OsSync(pPager->fd, 0);

}

pPager->state = PAGER_SYNCED;

}else if( MEMDB && nTrunc!=0 ){

rc = sqlite3pager_truncate(pPager, nTrunc);

}

sync_exit:

return rc;

}

下图可以进一步解释该过程:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: