/ Check-in [8514a4fe]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Check that read-only pages are not being modified (disabled by default). (CVS 2331)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8514a4feb2a86e93c4251c491d394e861bb65edb
User & Date: danielk1977 2005-02-15 02:54:15
Context
2005-02-15
03:38
Ensure a database file is not truncated without an exclusive lock. Fix for ticket #1114. (CVS 2332) check-in: dcbc9833 user: danielk1977 tags: trunk
02:54
Check that read-only pages are not being modified (disabled by default). (CVS 2331) check-in: 8514a4fe user: danielk1977 tags: trunk
2005-02-14
20:48
Make sure that when a CREATE INDEX fails, it does not leave a residue behind that can corrupt the database. Ticket #1115. (CVS 2330) check-in: cbed92f3 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/pager.c.

    14     14   ** The pager is used to access a database disk file.  It implements
    15     15   ** atomic commit and rollback through the use of a journal file that
    16     16   ** is separate from the database file.  The pager also implements file
    17     17   ** locking to prevent two processes from writing the same database
    18     18   ** file simultaneously, or one process from reading the database while
    19     19   ** another is writing.
    20     20   **
    21         -** @(#) $Id: pager.c,v 1.188 2005/02/06 02:45:42 drh Exp $
           21  +** @(#) $Id: pager.c,v 1.189 2005/02/15 02:54:15 danielk1977 Exp $
    22     22   */
    23     23   #include "sqliteInt.h"
    24     24   #include "os.h"
    25     25   #include "pager.h"
    26     26   #include <assert.h>
    27     27   #include <string.h>
    28     28   
................................................................................
   164    164     u8 inJournal;                  /* TRUE if has been written to journal */
   165    165     u8 inStmt;                     /* TRUE if in the statement subjournal */
   166    166     u8 dirty;                      /* TRUE if we need to write back changes */
   167    167     u8 needSync;                   /* Sync journal before writing this page */
   168    168     u8 alwaysRollback;             /* Disable dont_rollback() for this page */
   169    169     short int nRef;                /* Number of users of this page */
   170    170     PgHdr *pDirty;                 /* Dirty pages sorted by PgHdr.pgno */
          171  +#ifdef SQLITE_CHECK_PAGES
          172  +  u32 pageHash;
          173  +#endif
   171    174     /* pPager->psAligned bytes of page data follow this header */
   172    175     /* Pager.nExtra bytes of local data follow the page data */
   173    176   };
   174    177   
   175    178   /*
   176    179   ** For an in-memory only database, some extra information is recorded about
   177    180   ** each page so that changes can be rolled back.  (Journal files are not
................................................................................
   446    449     if( pPager->errMask & PAGER_ERR_LOCK )    rc = SQLITE_PROTOCOL;
   447    450     if( pPager->errMask & PAGER_ERR_DISK )    rc = SQLITE_IOERR;
   448    451     if( pPager->errMask & PAGER_ERR_FULL )    rc = SQLITE_FULL;
   449    452     if( pPager->errMask & PAGER_ERR_MEM )     rc = SQLITE_NOMEM;
   450    453     if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
   451    454     return rc;
   452    455   }
          456  +
          457  +#ifdef SQLITE_CHECK_PAGES
          458  +/*
          459  +** Return a 32-bit hash of the page data for pPage.
          460  +*/
          461  +static u32 pager_pagehash(PgHdr *pPage){
          462  +  u32 hash = 0;
          463  +  int i;
          464  +  unsigned char *pData = (unsigned char *)PGHDR_TO_DATA(pPage);
          465  +  for(i=0; i<pPage->pPager->pageSize; i++){
          466  +    hash = (hash+i)^pData[i];
          467  +  }
          468  +  return hash;
          469  +}
          470  +
          471  +/*
          472  +** The CHECK_PAGE macro takes a PgHdr* as an argument. If SQLITE_CHECK_PAGES
          473  +** is defined, and NDEBUG is not defined, an assert() statement checks
          474  +** that the page is either dirty or still matches the calculated page-hash.
          475  +*/
          476  +#define CHECK_PAGE(x) checkPage(x)
          477  +static void checkPage(PgHdr *pPg){
          478  +  Pager *pPager = pPg->pPager;
          479  +  assert( !pPg->pageHash || pPager->errMask || MEMDB || pPg->dirty || 
          480  +      pPg->pageHash==pager_pagehash(pPg) );
          481  +}
          482  +
          483  +#else
          484  +#define CHECK_PAGE(x)
          485  +#endif
   453    486   
   454    487   /*
   455    488   ** When this is called the journal file for pager pPager must be open.
   456    489   ** The master journal file name is read from the end of the file and 
   457    490   ** written into memory obtained from sqliteMalloc(). *pzMaster is
   458    491   ** set to point at the memory and SQLITE_OK returned. The caller must
   459    492   ** sqliteFree() *pzMaster.
................................................................................
   837    870       sqlite3OsDelete(pPager->zJournal);
   838    871       sqliteFree( pPager->aInJournal );
   839    872       pPager->aInJournal = 0;
   840    873       for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
   841    874         pPg->inJournal = 0;
   842    875         pPg->dirty = 0;
   843    876         pPg->needSync = 0;
          877  +#ifdef SQLITE_CHECK_PAGES
          878  +      pPg->pageHash = pager_pagehash(pPg);
          879  +#endif
   844    880       }
   845    881       pPager->dirtyCache = 0;
   846    882       pPager->nRec = 0;
   847    883     }else{
   848    884       assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
   849    885     }
   850    886     rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK);
................................................................................
   954    990       memcpy(pData, aData, pPager->pageSize);
   955    991       if( pPager->xDestructor ){  /*** FIX ME:  Should this be xReinit? ***/
   956    992         pPager->xDestructor(pData, pPager->pageSize);
   957    993       }
   958    994       if( pPager->state>=PAGER_EXCLUSIVE ){
   959    995         pPg->dirty = 0;
   960    996         pPg->needSync = 0;
          997  +#ifdef SQLITE_CHECK_PAGES
          998  +      pPg->pageHash = pager_pagehash(pPg);
          999  +#endif
   961   1000       }
   962   1001       CODEC(pPager, pData, pPg->pgno, 3);
   963   1002     }
   964   1003     return rc;
   965   1004   }
   966   1005   
   967   1006   /*
................................................................................
  1082   1121           pPager->xReiniter(PGHDR_TO_DATA(pPg), pPager->pageSize);
  1083   1122         }else{
  1084   1123           memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
  1085   1124         }
  1086   1125       }
  1087   1126       pPg->needSync = 0;
  1088   1127       pPg->dirty = 0;
         1128  +#ifdef SQLITE_CHECK_PAGES
         1129  +    pPg->pageHash = pager_pagehash(pPg);
         1130  +#endif
  1089   1131     }
  1090   1132     return rc;
  1091   1133   }
  1092   1134   
  1093   1135   /*
  1094   1136   ** Truncate the main file of the given pager to the number of pages
  1095   1137   ** indicated.
................................................................................
  2097   2139   #ifndef NDEBUG
  2098   2140       else{
  2099   2141         TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
  2100   2142       }
  2101   2143   #endif
  2102   2144       if( rc ) return rc;
  2103   2145       pList->dirty = 0;
         2146  +#ifdef SQLITE_CHECK_PAGES
         2147  +    pList->pageHash = pager_pagehash(pList);
         2148  +#endif
  2104   2149       pList = pList->pDirty;
  2105   2150     }
  2106   2151     return SQLITE_OK;
  2107   2152   }
  2108   2153   
  2109   2154   /*
  2110   2155   ** Collect every dirty page into a dirty list and
................................................................................
  2384   2429           }else{
  2385   2430             memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
  2386   2431           }
  2387   2432         }else{
  2388   2433           pPager->nRead++;
  2389   2434         }
  2390   2435       }
         2436  +#ifdef SQLITE_CHECK_PAGES
         2437  +    pPg->pageHash = pager_pagehash(pPg);
         2438  +#endif
  2391   2439     }else{
  2392   2440       /* The requested page is in the page cache. */
  2393   2441       pPager->nHit++;
  2394   2442       page_ref(pPg);
  2395   2443     }
  2396   2444     *ppPage = PGHDR_TO_DATA(pPg);
  2397   2445     return SQLITE_OK;
................................................................................
  2435   2483   
  2436   2484     /* Decrement the reference count for this page
  2437   2485     */
  2438   2486     pPg = DATA_TO_PGHDR(pData);
  2439   2487     assert( pPg->nRef>0 );
  2440   2488     pPg->nRef--;
  2441   2489     REFINFO(pPg);
         2490  +
         2491  +  CHECK_PAGE(pPg);
  2442   2492   
  2443   2493     /* When the number of references to a page reach 0, call the
  2444   2494     ** destructor and add the page to the freelist.
  2445   2495     */
  2446   2496     if( pPg->nRef==0 ){
  2447   2497       Pager *pPager;
  2448   2498       pPager = pPg->pPager;
................................................................................
  2623   2673       return pager_errcode(pPager);
  2624   2674     }
  2625   2675     if( pPager->readOnly ){
  2626   2676       return SQLITE_PERM;
  2627   2677     }
  2628   2678   
  2629   2679     assert( !pPager->setMaster );
         2680  +
         2681  +  CHECK_PAGE(pPg);
  2630   2682   
  2631   2683     /* Mark the page as dirty.  If the page has already been written
  2632   2684     ** to the journal then we can return right away.
  2633   2685     */
  2634   2686     pPg->dirty = 1;
  2635   2687     if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
  2636   2688       pPager->dirtyCache = 1;
................................................................................
  2827   2879         ** size. If you do not write this page and the size of the file
  2828   2880         ** on the disk ends up being too small, that can lead to database
  2829   2881         ** corruption during the next transaction.
  2830   2882         */
  2831   2883       }else{
  2832   2884         TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
  2833   2885         pPg->dirty = 0;
         2886  +#ifdef SQLITE_CHECK_PAGES
         2887  +      pPg->pageHash = pager_pagehash(pPg);
         2888  +#endif
  2834   2889       }
  2835   2890     }
  2836   2891   }
  2837   2892   
  2838   2893   /*
  2839   2894   ** A call to this routine tells the pager that if a rollback occurs,
  2840   2895   ** it is not necessary to restore the data on the given page.  This