mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Patch the sqlite3PagerWrite() method in the Pager to run a bit faster.
FossilOrigin-Name: c63311e2f3344363a5ed99838fb5850004eaee30
This commit is contained in:
185
src/pager.c
185
src/pager.c
@@ -5772,6 +5772,97 @@ static int pager_write(PgHdr *pPg){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** This is a variant of sqlite3PagerWrite() that runs when the sector size
|
||||
** is larger than the page size. SQLite makes the (reasonable) assumption that
|
||||
** all bytes of a sector are written together by hardware. Hence, all bytes of
|
||||
** a sector need to be journalled in case of a power loss in the middle of
|
||||
** a write.
|
||||
**
|
||||
** Usually, the sector size is less than or equal to the page size, in which
|
||||
** case pages can be individually written. This routine only runs in the exceptional
|
||||
** case where the page size is smaller than the sector size.
|
||||
*/
|
||||
static SQLITE_NOINLINE int pagerWriteLargeSector(PgHdr *pPg){
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
Pgno nPageCount; /* Total number of pages in database file */
|
||||
Pgno pg1; /* First page of the sector pPg is located on. */
|
||||
int nPage = 0; /* Number of pages starting at pg1 to journal */
|
||||
int ii; /* Loop counter */
|
||||
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
|
||||
Pager *pPager = pPg->pPager; /* The pager that owns pPg */
|
||||
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
|
||||
|
||||
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
|
||||
** a journal header to be written between the pages journaled by
|
||||
** this function.
|
||||
*/
|
||||
assert( !MEMDB );
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
|
||||
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
|
||||
|
||||
/* This trick assumes that both the page-size and sector-size are
|
||||
** an integer power of 2. It sets variable pg1 to the identifier
|
||||
** of the first page of the sector pPg is located on.
|
||||
*/
|
||||
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
|
||||
|
||||
nPageCount = pPager->dbSize;
|
||||
if( pPg->pgno>nPageCount ){
|
||||
nPage = (pPg->pgno - pg1)+1;
|
||||
}else if( (pg1+nPagePerSector-1)>nPageCount ){
|
||||
nPage = nPageCount+1-pg1;
|
||||
}else{
|
||||
nPage = nPagePerSector;
|
||||
}
|
||||
assert(nPage>0);
|
||||
assert(pg1<=pPg->pgno);
|
||||
assert((pg1+nPage)>pPg->pgno);
|
||||
|
||||
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
|
||||
Pgno pg = pg1+ii;
|
||||
PgHdr *pPage;
|
||||
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
|
||||
if( pg!=PAGER_MJ_PGNO(pPager) ){
|
||||
rc = sqlite3PagerGet(pPager, pg, &pPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_write(pPage);
|
||||
if( pPage->flags&PGHDR_NEED_SYNC ){
|
||||
needSync = 1;
|
||||
}
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
}else if( (pPage = pager_lookup(pPager, pg))!=0 ){
|
||||
if( pPage->flags&PGHDR_NEED_SYNC ){
|
||||
needSync = 1;
|
||||
}
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
|
||||
** starting at pg1, then it needs to be set for all of them. Because
|
||||
** writing to any of these nPage pages may damage the others, the
|
||||
** journal file must contain sync()ed copies of all of them
|
||||
** before any of them can be written out to the database file.
|
||||
*/
|
||||
if( rc==SQLITE_OK && needSync ){
|
||||
assert( !MEMDB );
|
||||
for(ii=0; ii<nPage; ii++){
|
||||
PgHdr *pPage = pager_lookup(pPager, pg1+ii);
|
||||
if( pPage ){
|
||||
pPage->flags |= PGHDR_NEED_SYNC;
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
|
||||
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Mark a data page as writeable. This routine must be called before
|
||||
** making changes to a page. The caller must check the return value
|
||||
@@ -5786,96 +5877,16 @@ static int pager_write(PgHdr *pPg){
|
||||
** If an error occurs, SQLITE_NOMEM or an IO error code is returned
|
||||
** as appropriate. Otherwise, SQLITE_OK.
|
||||
*/
|
||||
int sqlite3PagerWrite(DbPage *pDbPage){
|
||||
int rc = SQLITE_OK;
|
||||
|
||||
PgHdr *pPg = pDbPage;
|
||||
Pager *pPager = pPg->pPager;
|
||||
|
||||
int sqlite3PagerWrite(PgHdr *pPg){
|
||||
assert( (pPg->flags & PGHDR_MMAP)==0 );
|
||||
assert( pPager->eState>=PAGER_WRITER_LOCKED );
|
||||
assert( pPager->eState!=PAGER_ERROR );
|
||||
assert( assert_pager_state(pPager) );
|
||||
|
||||
if( pPager->sectorSize > (u32)pPager->pageSize ){
|
||||
Pgno nPageCount; /* Total number of pages in database file */
|
||||
Pgno pg1; /* First page of the sector pPg is located on. */
|
||||
int nPage = 0; /* Number of pages starting at pg1 to journal */
|
||||
int ii; /* Loop counter */
|
||||
int needSync = 0; /* True if any page has PGHDR_NEED_SYNC */
|
||||
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
|
||||
|
||||
/* Set the doNotSpill NOSYNC bit to 1. This is because we cannot allow
|
||||
** a journal header to be written between the pages journaled by
|
||||
** this function.
|
||||
*/
|
||||
assert( !MEMDB );
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)==0 );
|
||||
pPager->doNotSpill |= SPILLFLAG_NOSYNC;
|
||||
|
||||
/* This trick assumes that both the page-size and sector-size are
|
||||
** an integer power of 2. It sets variable pg1 to the identifier
|
||||
** of the first page of the sector pPg is located on.
|
||||
*/
|
||||
pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
|
||||
|
||||
nPageCount = pPager->dbSize;
|
||||
if( pPg->pgno>nPageCount ){
|
||||
nPage = (pPg->pgno - pg1)+1;
|
||||
}else if( (pg1+nPagePerSector-1)>nPageCount ){
|
||||
nPage = nPageCount+1-pg1;
|
||||
}else{
|
||||
nPage = nPagePerSector;
|
||||
}
|
||||
assert(nPage>0);
|
||||
assert(pg1<=pPg->pgno);
|
||||
assert((pg1+nPage)>pPg->pgno);
|
||||
|
||||
for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
|
||||
Pgno pg = pg1+ii;
|
||||
PgHdr *pPage;
|
||||
if( pg==pPg->pgno || !sqlite3BitvecTest(pPager->pInJournal, pg) ){
|
||||
if( pg!=PAGER_MJ_PGNO(pPager) ){
|
||||
rc = sqlite3PagerGet(pPager, pg, &pPage);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = pager_write(pPage);
|
||||
if( pPage->flags&PGHDR_NEED_SYNC ){
|
||||
needSync = 1;
|
||||
}
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
}else if( (pPage = pager_lookup(pPager, pg))!=0 ){
|
||||
if( pPage->flags&PGHDR_NEED_SYNC ){
|
||||
needSync = 1;
|
||||
}
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the PGHDR_NEED_SYNC flag is set for any of the nPage pages
|
||||
** starting at pg1, then it needs to be set for all of them. Because
|
||||
** writing to any of these nPage pages may damage the others, the
|
||||
** journal file must contain sync()ed copies of all of them
|
||||
** before any of them can be written out to the database file.
|
||||
*/
|
||||
if( rc==SQLITE_OK && needSync ){
|
||||
assert( !MEMDB );
|
||||
for(ii=0; ii<nPage; ii++){
|
||||
PgHdr *pPage = pager_lookup(pPager, pg1+ii);
|
||||
if( pPage ){
|
||||
pPage->flags |= PGHDR_NEED_SYNC;
|
||||
sqlite3PagerUnrefNotNull(pPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert( (pPager->doNotSpill & SPILLFLAG_NOSYNC)!=0 );
|
||||
pPager->doNotSpill &= ~SPILLFLAG_NOSYNC;
|
||||
assert( pPg->pPager->eState>=PAGER_WRITER_LOCKED );
|
||||
assert( pPg->pPager->eState!=PAGER_ERROR );
|
||||
assert( assert_pager_state(pPg->pPager) );
|
||||
if( pPg->pPager->sectorSize > (u32)pPg->pPager->pageSize ){
|
||||
return pagerWriteLargeSector(pPg);
|
||||
}else{
|
||||
rc = pager_write(pDbPage);
|
||||
return pager_write(pPg);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user