Patch the sqlite3PagerWrite() method in the Pager to run a bit faster.

FossilOrigin-Name: c63311e2f3344363a5ed99838fb5850004eaee30
This commit is contained in:
drh 2014-08-24 01:32:43 +00:00
parent efbf044583
commit f063e08fd9
3 changed files with 105 additions and 94 deletions

View File

@ -1,5 +1,5 @@
C Faster\simplementation\sof\spcache1Fetch()
D 2014-08-23T23:15:31.233
C Patch\sthe\ssqlite3PagerWrite()\smethod\sin\sthe\sPager\sto\srun\sa\sbit\sfaster.
D 2014-08-24T01:32:43.379
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5eb79e334a5de69c87740edd56af6527dd219308
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -211,7 +211,7 @@ F src/os_setup.h c9d4553b5aaa6f73391448b265b89bed0b890faa
F src/os_unix.c bd7df3094a60915c148517504c76df4fca24e542
F src/os_win.c d067fce558a5032e6e6afe62899e5397bf63cf3e
F src/os_win.h 09e751b20bbc107ffbd46e13555dc73576d88e21
F src/pager.c f6bb1fa6cdf2062f2d8aec3e64db302bca519ab8
F src/pager.c c831b0df879114915c08dc5a0188f9f22c48403b
F src/pager.h ffd5607f7b3e4590b415b007a4382f693334d428
F src/parse.y 22d6a074e5f5a7258947a1dc55a9bf946b765dd0
F src/pcache.c da602c5447051705cab41604bf3276815eb569d0
@ -1188,7 +1188,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P bd41d394d48516eb7d8ddc46abdcb427aa80173e
R d2491d65f44f8709d1d156c840c25703
P 0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
R 2fe545d9c9446b3adf94c91625adc119
U drh
Z 15bb2365f5f8da3e5de34ee820ad0674
Z 79e99766e8b4bdebd57118e507ef67dc

View File

@ -1 +1 @@
0371cc3bb07448bcd64fd671f3e71bb7f30deb4d
c63311e2f3344363a5ed99838fb5850004eaee30

View File

@ -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;
}
/*