Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -356,10 +356,11 @@ u8 changeCountDone; /* Set after incrementing the change-counter */ u32 vfsFlags; /* Flags for sqlite3_vfs.xOpen() */ int errCode; /* One of several kinds of errors */ int dbSize; /* Number of pages in the file */ int origDbSize; /* dbSize before the current change */ + int hintDbSize; /* dbSize sent to SQLITE_FCNTL_SIZE_HINT */ int stmtSize; /* Size of database (in pages) at stmt_begin() */ int nRec; /* Number of pages written to the journal */ u32 cksumInit; /* Quasi-random value added to every checksum */ int stmtNRec; /* Number of records in stmt subjournal */ int nExtra; /* Add this many bytes to each in-memory page */ @@ -1356,10 +1357,11 @@ pPager->stmtInUse = 0; pPager->journalOff = 0; pPager->journalStarted = 0; pPager->stmtAutoopen = 0; pPager->origDbSize = 0; + pPager->hintDbSize = 0; } } if( !MEMDB || pPager->errCode==SQLITE_OK ){ pPager->state = PAGER_UNLOCK; @@ -1455,10 +1457,11 @@ pPager->state = PAGER_SHARED; }else if( pPager->state==PAGER_SYNCED ){ pPager->state = PAGER_EXCLUSIVE; } pPager->origDbSize = 0; + pPager->hintDbSize = 0; pPager->setMaster = 0; pPager->needSync = 0; lruListSetFirstSynced(pPager); pPager->dbSize = -1; pPager->dbModified = 0; @@ -3030,10 +3033,12 @@ */ static int pager_write_pagelist(PgHdr *pList){ Pager *pPager; PgHdr *p; int rc; + Pgno mxPgno; /* Maximum page number to be written */ + int nExtend = 0; /* Number of pages on pList that extend the file */ if( pList==0 ) return SQLITE_OK; pPager = pList->pPager; /* At this point there may be either a RESERVED or EXCLUSIVE lock on the @@ -3059,10 +3064,12 @@ pList = sort_pagelist(pList); for(p=pList; p; p=p->pDirty){ assert( p->dirty ); p->dirty = 0; + mxPgno = p->pgno; + if( p->pgno>pPager->hintDbSize ) nExtend++; } /* If the file has not yet been opened, open it now. */ if( !pPager->fd->pMethods ){ assert(pPager->tempFile); @@ -3071,13 +3078,17 @@ } /* Before the first write, give the VFS a hint of what the final ** file size will be. */ - if( pPager->dbSize > (pPager->origDbSize+1) ){ - sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; + if( nExtend>1 || (nExtend==1 && pPager->dbSize>mxPgno) ){ + sqlite3_int64 szFile; + assert( pPager->hintDbSizedbSize ); + szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); + pPager->hintDbSize = pPager->dbSize; } while( pList ){ /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3PagerTruncate() was called to @@ -4023,11 +4034,11 @@ pPager->nRec = 0; if( pPager->errCode ){ rc = pPager->errCode; goto failed_to_open_journal; } - pPager->origDbSize = pPager->dbSize; + pPager->hintDbSize = pPager->origDbSize = pPager->dbSize; rc = writeJournalHdr(pPager); if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3PagerStmtBegin(pPager); @@ -4081,11 +4092,11 @@ assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ assert( pPager->pInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; - pPager->origDbSize = pPager->dbSize; + pPager->hintDbSize = pPager->origDbSize = pPager->dbSize; }else{ rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); if( rc==SQLITE_OK ){ pPager->state = PAGER_RESERVED; if( exFlag ){ @@ -4110,19 +4121,20 @@ ** kept open and either was truncated to 0 bytes or its header was ** overwritten with zeros. */ assert( pPager->nRec==0 ); assert( pPager->origDbSize==0 ); + assert( pPager->hintDbSize==0 ); assert( pPager->pInJournal==0 ); sqlite3PagerPagecount(pPager, 0); pagerLeave(pPager); pPager->pInJournal = sqlite3BitvecCreate( pPager->dbSize ); pagerEnter(pPager); if( !pPager->pInJournal ){ rc = SQLITE_NOMEM; }else{ - pPager->origDbSize = pPager->dbSize; + pPager->hintDbSize = pPager->origDbSize = pPager->dbSize; rc = writeJournalHdr(pPager); } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); pagerLeave(pPager); @@ -4913,11 +4925,11 @@ pPager->xReiniter(p, pPager->pageSize); } } pPager->pDirty = 0; pPager->pStmt = 0; - pPager->dbSize = pPager->origDbSize; + pPager->dbSize = pPager->hintDbSize = pPager->origDbSize; pager_truncate_cache(pPager); pPager->stmtInUse = 0; pPager->state = PAGER_SHARED; return SQLITE_OK; } Index: test/io.test ================================================================== --- test/io.test +++ test/io.test @@ -399,11 +399,11 @@ INSERT INTO abc SELECT * FROM abc; } # File has grown - showing there was a cache-spill - but there # have been no calls to fsync(): list [file size test.db] [nSync] - } {38912 0} + } {36864 0} do_test io-3.3 { # The COMMIT requires a single fsync() - to the database file. execsql { COMMIT } list [file size test.db] [nSync] } {39936 1}