Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.188 2005/02/06 02:45:42 drh Exp $ +** @(#) $Id: pager.c,v 1.189 2005/02/15 02:54:15 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include "pager.h" #include @@ -166,10 +166,13 @@ u8 dirty; /* TRUE if we need to write back changes */ u8 needSync; /* Sync journal before writing this page */ u8 alwaysRollback; /* Disable dont_rollback() for this page */ short int nRef; /* Number of users of this page */ PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */ +#ifdef SQLITE_CHECK_PAGES + u32 pageHash; +#endif /* pPager->psAligned bytes of page data follow this header */ /* Pager.nExtra bytes of local data follow the page data */ }; /* @@ -448,10 +451,40 @@ if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL; if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM; if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT; return rc; } + +#ifdef SQLITE_CHECK_PAGES +/* +** Return a 32-bit hash of the page data for pPage. +*/ +static u32 pager_pagehash(PgHdr *pPage){ + u32 hash = 0; + int i; + unsigned char *pData = (unsigned char *)PGHDR_TO_DATA(pPage); + for(i=0; ipPager->pageSize; i++){ + hash = (hash+i)^pData[i]; + } + return hash; +} + +/* +** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES +** is defined, and NDEBUG is not defined, an assert() statement checks +** that the page is either dirty or still matches the calculated page-hash. +*/ +#define CHECK_PAGE(x) checkPage(x) +static void checkPage(PgHdr *pPg){ + Pager *pPager = pPg->pPager; + assert( !pPg->pageHash || pPager->errMask || MEMDB || pPg->dirty || + pPg->pageHash==pager_pagehash(pPg) ); +} + +#else +#define CHECK_PAGE(x) +#endif /* ** When this is called the journal file for pager pPager must be open. ** The master journal file name is read from the end of the file and ** written into memory obtained from sqliteMalloc(). *pzMaster is @@ -839,10 +872,13 @@ pPager->aInJournal = 0; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ pPg->inJournal = 0; pPg->dirty = 0; pPg->needSync = 0; +#ifdef SQLITE_CHECK_PAGES + pPg->pageHash = pager_pagehash(pPg); +#endif } pPager->dirtyCache = 0; pPager->nRec = 0; }else{ assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); @@ -956,10 +992,13 @@ pPager->xDestructor(pData, pPager->pageSize); } if( pPager->state>=PAGER_EXCLUSIVE ){ pPg->dirty = 0; pPg->needSync = 0; +#ifdef SQLITE_CHECK_PAGES + pPg->pageHash = pager_pagehash(pPg); +#endif } CODEC(pPager, pData, pPg->pgno, 3); } return rc; } @@ -1084,10 +1123,13 @@ memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra); } } pPg->needSync = 0; pPg->dirty = 0; +#ifdef SQLITE_CHECK_PAGES + pPg->pageHash = pager_pagehash(pPg); +#endif } return rc; } /* @@ -2099,10 +2141,13 @@ TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno); } #endif if( rc ) return rc; pList->dirty = 0; +#ifdef SQLITE_CHECK_PAGES + pList->pageHash = pager_pagehash(pList); +#endif pList = pList->pDirty; } return SQLITE_OK; } @@ -2386,10 +2431,13 @@ } }else{ pPager->nRead++; } } +#ifdef SQLITE_CHECK_PAGES + pPg->pageHash = pager_pagehash(pPg); +#endif }else{ /* The requested page is in the page cache. */ pPager->nHit++; page_ref(pPg); } @@ -2437,10 +2485,12 @@ */ pPg = DATA_TO_PGHDR(pData); assert( pPg->nRef>0 ); pPg->nRef--; REFINFO(pPg); + + CHECK_PAGE(pPg); /* When the number of references to a page reach 0, call the ** destructor and add the page to the freelist. */ if( pPg->nRef==0 ){ @@ -2625,10 +2675,12 @@ if( pPager->readOnly ){ return SQLITE_PERM; } assert( !pPager->setMaster ); + + CHECK_PAGE(pPg); /* Mark the page as dirty. If the page has already been written ** to the journal then we can return right away. */ pPg->dirty = 1; @@ -2829,10 +2881,13 @@ ** corruption during the next transaction. */ }else{ TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager)); pPg->dirty = 0; +#ifdef SQLITE_CHECK_PAGES + pPg->pageHash = pager_pagehash(pPg); +#endif } } } /*