/ Check-in [866216c0]
Login

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

Overview
Comment:Further simplifications to pager.c in support of structural coverage testing. (CVS 6929)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 866216c0b6ba23b66483046fb402ddbe4f9a7b14
User & Date: drh 2009-07-24 19:01:19
References
2009-11-06
03:04 New ticket [0bf974bd] backup api asserts with zero length source file. artifact: fcecca71 user: shane
Context
2009-07-24
21:23
Fix an issue with the previous check-in, (6929). (CVS 6930) check-in: e5165c80 user: drh tags: trunk
19:01
Further simplifications to pager.c in support of structural coverage testing. (CVS 6929) check-in: 866216c0 user: drh tags: trunk
17:58
Allow virtual tables to be used in shared-cache mode. (CVS 6928) check-in: 5d9e767a user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.702 2009/07/24 17:58:53 danielk1977 Exp $
           12  +** $Id: btree.c,v 1.703 2009/07/24 19:01:19 drh Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** See the header comment on "btreeInt.h" for additional information.
    16     16   ** Including a description of file format and an overview of operation.
    17     17   */
    18     18   #include "btreeInt.h"
    19     19   
................................................................................
  1758   1758     
  1759   1759       pBt = sqlite3MallocZero( sizeof(*pBt) );
  1760   1760       if( pBt==0 ){
  1761   1761         rc = SQLITE_NOMEM;
  1762   1762         goto btree_open_out;
  1763   1763       }
  1764   1764       rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
  1765         -                          EXTRA_SIZE, flags, vfsFlags);
         1765  +                          EXTRA_SIZE, flags, vfsFlags, pageReinit);
  1766   1766       if( rc==SQLITE_OK ){
  1767   1767         rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
  1768   1768       }
  1769   1769       if( rc!=SQLITE_OK ){
  1770   1770         goto btree_open_out;
  1771   1771       }
  1772   1772       pBt->db = db;
  1773   1773       sqlite3PagerSetBusyhandler(pBt->pPager, btreeInvokeBusyHandler, pBt);
  1774   1774       p->pBt = pBt;
  1775   1775     
  1776         -    sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
  1777   1776       pBt->pCursor = 0;
  1778   1777       pBt->pPage1 = 0;
  1779   1778       pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
  1780   1779       pBt->pageSize = get2byte(&zDbHeader[16]);
  1781   1780       if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
  1782   1781            || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
  1783   1782         pBt->pageSize = 0;

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.615 2009/07/24 16:32:01 drh Exp $
           21  +** @(#) $Id: pager.c,v 1.616 2009/07/24 19:01:19 drh Exp $
    22     22   */
    23     23   #ifndef SQLITE_OMIT_DISKIO
    24     24   #include "sqliteInt.h"
    25     25   
    26     26   /*
    27     27   ** Macros for troubleshooting.  Normally turned off
    28     28   */
................................................................................
  1319   1319        || pPager->journalMode==PAGER_JOURNALMODE_PERSIST
  1320   1320       ){
  1321   1321         rc = zeroJournalHdr(pPager, hasMaster);
  1322   1322         pager_error(pPager, rc);
  1323   1323         pPager->journalOff = 0;
  1324   1324         pPager->journalStarted = 0;
  1325   1325       }else{
  1326         -      assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE || rc );
         1326  +      assert( pPager->journalMode==PAGER_JOURNALMODE_DELETE );
  1327   1327         sqlite3OsClose(pPager->jfd);
  1328         -      if( rc==SQLITE_OK && !pPager->tempFile ){
         1328  +      if( !pPager->tempFile ){
  1329   1329           rc = sqlite3OsDelete(pPager->pVfs, pPager->zJournal, 0);
  1330   1330         }
  1331   1331       }
  1332   1332   
  1333   1333   #ifdef SQLITE_CHECK_PAGES
  1334   1334       sqlite3PcacheIterateDirty(pPager->pPCache, pager_set_pagehash);
  1335   1335   #endif
................................................................................
  1571   1571       ** database active. However such a page may be rolled back as a result
  1572   1572       ** of an internal error resulting in an automatic call to
  1573   1573       ** sqlite3PagerRollback().
  1574   1574       */
  1575   1575       void *pData;
  1576   1576       pData = pPg->pData;
  1577   1577       memcpy(pData, aData, pPager->pageSize);
  1578         -    if( pPager->xReiniter ){
  1579         -      pPager->xReiniter(pPg);
  1580         -    }
         1578  +    pPager->xReiniter(pPg);
  1581   1579       if( isMainJrnl && (!isSavepnt || *pOffset<=pPager->journalHdr) ){
  1582   1580         /* If the contents of this page were just restored from the main 
  1583   1581         ** journal file, then its content must be as they were when the 
  1584   1582         ** transaction was first opened. In this case we can mark the page
  1585   1583         ** as clean, since there will be no need to write it out to the.
  1586   1584         **
  1587   1585         ** There is one exception to this rule. If the page is being rolled
................................................................................
  2357   2355     int (*xBusyHandler)(void *),         /* Pointer to busy-handler function */
  2358   2356     void *pBusyHandlerArg                /* Argument to pass to xBusyHandler */
  2359   2357   ){  
  2360   2358     pPager->xBusyHandler = xBusyHandler;
  2361   2359     pPager->pBusyHandlerArg = pBusyHandlerArg;
  2362   2360   }
  2363   2361   
  2364         -/*
  2365         -** Set the reinitializer for this pager. If not NULL, the reinitializer
  2366         -** is called when the content of a page in cache is modified (restored)
  2367         -** as part of a transaction or savepoint rollback. The callback gives 
  2368         -** higher-level code an opportunity to restore the EXTRA section to 
  2369         -** agree with the restored page data.
  2370         -*/
  2371         -void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*)){
  2372         -  pPager->xReiniter = xReinit;
  2373         -}
  2374         -
  2375   2362   /*
  2376   2363   ** Report the current page size and number of reserved bytes back
  2377   2364   ** to the codec.
  2378   2365   */
  2379   2366   #ifdef SQLITE_HAS_CODEC
  2380   2367   static void pagerReportSize(Pager *pPager){
  2381   2368     if( pPager->xCodecSizeChng ){
................................................................................
  3140   3127   */
  3141   3128   int sqlite3PagerOpen(
  3142   3129     sqlite3_vfs *pVfs,       /* The virtual file system to use */
  3143   3130     Pager **ppPager,         /* OUT: Return the Pager structure here */
  3144   3131     const char *zFilename,   /* Name of the database file to open */
  3145   3132     int nExtra,              /* Extra bytes append to each in-memory page */
  3146   3133     int flags,               /* flags controlling this file */
  3147         -  int vfsFlags             /* flags passed through to sqlite3_vfs.xOpen() */
         3134  +  int vfsFlags,            /* flags passed through to sqlite3_vfs.xOpen() */
         3135  +  void (*xReinit)(DbPage*) /* Function to reinitialize pages */
  3148   3136   ){
  3149   3137     u8 *pPtr;
  3150   3138     Pager *pPager = 0;       /* Pager object to allocate and return */
  3151   3139     int rc = SQLITE_OK;      /* Return code */
  3152   3140     int tempFile = 0;        /* True for temp files (incl. in-memory files) */
  3153   3141     int memDb = 0;           /* True if this is an in-memory file */
  3154   3142     int readOnly = 0;        /* True if this is a read-only file */
................................................................................
  3359   3347             || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
  3360   3348     assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
  3361   3349     pPager->exclusiveMode = (u8)tempFile; 
  3362   3350     pPager->changeCountDone = pPager->tempFile;
  3363   3351     pPager->memDb = (u8)memDb;
  3364   3352     pPager->readOnly = (u8)readOnly;
  3365   3353     /* pPager->needSync = 0; */
  3366         -  pPager->noSync = (pPager->tempFile || !useJournal) ?1:0;
         3354  +  assert( useJournal || pPager->tempFile );
         3355  +  pPager->noSync = pPager->tempFile;
  3367   3356     pPager->fullSync = pPager->noSync ?0:1;
  3368   3357     pPager->sync_flags = SQLITE_SYNC_NORMAL;
  3369   3358     /* pPager->pFirst = 0; */
  3370   3359     /* pPager->pFirstSynced = 0; */
  3371   3360     /* pPager->pLast = 0; */
  3372   3361     pPager->nExtra = (u16)nExtra;
  3373   3362     pPager->journalSizeLimit = SQLITE_DEFAULT_JOURNAL_SIZE_LIMIT;
  3374   3363     assert( isOpen(pPager->fd) || tempFile );
  3375   3364     setSectorSize(pPager);
  3376         -  if( memDb ){
         3365  +  if( !useJournal ){
         3366  +    pPager->journalMode = PAGER_JOURNALMODE_OFF;
         3367  +  }else if( memDb ){
  3377   3368       pPager->journalMode = PAGER_JOURNALMODE_MEMORY;
  3378   3369     }
  3379   3370     /* pPager->xBusyHandler = 0; */
  3380   3371     /* pPager->pBusyHandlerArg = 0; */
         3372  +  pPager->xReiniter = xReinit;
  3381   3373     /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
  3382   3374     *ppPager = pPager;
  3383   3375     return SQLITE_OK;
  3384   3376   }
  3385   3377   
  3386   3378   
  3387   3379   
................................................................................
  3418   3410   */
  3419   3411   static int hasHotJournal(Pager *pPager, int *pExists){
  3420   3412     sqlite3_vfs * const pVfs = pPager->pVfs;
  3421   3413     int rc;                       /* Return code */
  3422   3414     int exists;                   /* True if a journal file is present */
  3423   3415   
  3424   3416     assert( pPager!=0 );
  3425         -  assert( pPager->useJournal );
         3417  +  assert( useJournal );
  3426   3418     assert( isOpen(pPager->fd) );
  3427   3419     assert( !isOpen(pPager->jfd) );
  3428   3420   
  3429   3421     *pExists = 0;
  3430   3422     rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
  3431   3423     if( rc==SQLITE_OK && exists ){
  3432   3424       int locked;                 /* True if some process holds a RESERVED lock */
................................................................................
  3514   3506   static int readDbPage(PgHdr *pPg){
  3515   3507     Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
  3516   3508     Pgno pgno = pPg->pgno;       /* Page number to read */
  3517   3509     int rc;                      /* Return code */
  3518   3510     i64 iOffset;                 /* Byte offset of file to read from */
  3519   3511   
  3520   3512     assert( pPager->state>=PAGER_SHARED && !MEMDB );
         3513  +  assert( isOpen(pPager->fd) );
  3521   3514   
  3522   3515     if( !isOpen(pPager->fd) ){
  3523   3516       assert( pPager->tempFile );
  3524   3517       memset(pPg->pData, 0, pPager->pageSize);
  3525   3518       return SQLITE_OK;
  3526   3519     }
  3527   3520     iOffset = (pgno-1)*(i64)pPager->pageSize;
................................................................................
  3893   3886           /* Failure to set the bits in the InJournal bit-vectors is benign.
  3894   3887           ** It merely means that we might do some extra work to journal a 
  3895   3888           ** page that does not need to be journaled.  Nevertheless, be sure 
  3896   3889           ** to test the case where a malloc error occurs while trying to set 
  3897   3890           ** a bit in a bit vector.
  3898   3891           */
  3899   3892           sqlite3BeginBenignMalloc();
  3900         -        if( pgno<=pPager->dbOrigSize ){
         3893  +        if( ALWAYS(pgno<=pPager->dbOrigSize) ){
  3901   3894             TESTONLY( rc = ) sqlite3BitvecSet(pPager->pInJournal, pgno);
  3902   3895             testcase( rc==SQLITE_NOMEM );
  3903   3896           }
  3904   3897           TESTONLY( rc = ) addToSavepointBitvecs(pPager, pgno);
  3905   3898           testcase( rc==SQLITE_NOMEM );
  3906   3899           sqlite3EndBenignMalloc();
  3907   3900         }else{
................................................................................
  4017   4010   */
  4018   4011   static int pager_open_journal(Pager *pPager){
  4019   4012     int rc = SQLITE_OK;                        /* Return code */
  4020   4013     sqlite3_vfs * const pVfs = pPager->pVfs;   /* Local cache of vfs pointer */
  4021   4014   
  4022   4015     assert( pPager->state>=PAGER_RESERVED );
  4023   4016     assert( pPager->useJournal );
         4017  +  assert( pPager->journalMode!=PAGER_JOURNALMODE_OFF );
  4024   4018     assert( pPager->pInJournal==0 );
  4025   4019     
  4026   4020     /* If already in the error state, this function is a no-op.  But on
  4027   4021     ** the other hand, this routine is never called if we are already in
  4028   4022     ** an error state. */
  4029   4023     if( NEVER(pPager->errCode) ) return pPager->errCode;
  4030   4024   
................................................................................
  4111   4105   ** sub-journal. If the subjInMemory argument is zero, then any required
  4112   4106   ** sub-journal is implemented in-memory if pPager is an in-memory database, 
  4113   4107   ** or using a temporary file otherwise.
  4114   4108   */
  4115   4109   int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
  4116   4110     int rc = SQLITE_OK;
  4117   4111     assert( pPager->state!=PAGER_UNLOCK );
         4112  +  assert( pPager->useJournal );
  4118   4113     pPager->subjInMemory = (u8)subjInMemory;
  4119   4114     if( pPager->state==PAGER_SHARED ){
  4120   4115       assert( pPager->pInJournal==0 );
  4121   4116       assert( !MEMDB && !pPager->tempFile );
  4122   4117   
  4123   4118       /* Obtain a RESERVED lock on the database file. If the exFlag parameter
  4124   4119       ** is true, then immediately upgrade this to an EXCLUSIVE lock. The
................................................................................
  4132   4127           rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);
  4133   4128         }
  4134   4129       }
  4135   4130   
  4136   4131       /* If the required locks were successfully obtained, open the journal
  4137   4132       ** file and write the first journal-header to it.
  4138   4133       */
  4139         -    if( rc==SQLITE_OK && pPager->useJournal
  4140         -     && pPager->journalMode!=PAGER_JOURNALMODE_OFF 
  4141         -    ){
         4134  +    if( rc==SQLITE_OK && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
  4142   4135         rc = pager_open_journal(pPager);
  4143   4136       }
  4144   4137     }else if( isOpen(pPager->jfd) && pPager->journalOff==0 ){
  4145   4138       /* This happens when the pager was in exclusive-access mode the last
  4146   4139       ** time a (read or write) transaction was successfully concluded
  4147   4140       ** by this connection. Instead of deleting the journal file it was 
  4148   4141       ** kept open and either was truncated to 0 bytes or its header was
................................................................................
  4210   4203       */
  4211   4204       assert( pPager->state!=PAGER_UNLOCK );
  4212   4205       rc = sqlite3PagerBegin(pPager, 0, pPager->subjInMemory);
  4213   4206       if( rc!=SQLITE_OK ){
  4214   4207         return rc;
  4215   4208       }
  4216   4209       assert( pPager->state>=PAGER_RESERVED );
  4217         -    if( !isOpen(pPager->jfd) && pPager->useJournal
  4218         -          && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
         4210  +    if( !isOpen(pPager->jfd) && pPager->journalMode!=PAGER_JOURNALMODE_OFF ){
         4211  +      assert( pPager->useJournal );
  4219   4212         rc = pager_open_journal(pPager);
  4220   4213         if( rc!=SQLITE_OK ) return rc;
  4221   4214       }
  4222   4215       pPager->dbModified = 1;
  4223   4216     
  4224   4217       /* The transaction journal now exists and we have a RESERVED or an
  4225   4218       ** EXCLUSIVE lock on the main database file.  Write the current page to
................................................................................
  4485   4478     assert( isDirectMode==0 );
  4486   4479     UNUSED_PARAMETER(isDirectMode);
  4487   4480   #else
  4488   4481   # define DIRECT_MODE isDirectMode
  4489   4482   #endif
  4490   4483   
  4491   4484     assert( pPager->state>=PAGER_RESERVED );
  4492         -  if( !pPager->changeCountDone && pPager->dbSize>0 ){
         4485  +  if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){
  4493   4486       PgHdr *pPgHdr;                /* Reference to page 1 */
  4494   4487       u32 change_counter;           /* Initial value of change-counter field */
  4495   4488   
  4496   4489       assert( !pPager->tempFile && isOpen(pPager->fd) );
  4497   4490   
  4498   4491       /* Open page 1 of the file for writing. */
  4499   4492       rc = sqlite3PagerGet(pPager, 1, &pPgHdr);

Changes to src/pager.h.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This header file defines the interface that the sqlite page cache
    13     13   ** subsystem.  The page cache subsystem reads and writes a file a page
    14     14   ** at a time and provides a journal for rollback.
    15     15   **
    16         -** @(#) $Id: pager.h,v 1.103 2009/07/21 19:25:24 danielk1977 Exp $
           16  +** @(#) $Id: pager.h,v 1.104 2009/07/24 19:01:19 drh Exp $
    17     17   */
    18     18   
    19     19   #ifndef _PAGER_H_
    20     20   #define _PAGER_H_
    21     21   
    22     22   /*
    23     23   ** Default maximum size for persistent journal files. A negative 
................................................................................
    82     82   /*
    83     83   ** The remainder of this file contains the declarations of the functions
    84     84   ** that make up the Pager sub-system API. See source code comments for 
    85     85   ** a detailed description of each routine.
    86     86   */
    87     87   
    88     88   /* Open and close a Pager connection. */ 
    89         -int sqlite3PagerOpen(sqlite3_vfs *, Pager **ppPager, const char*, int,int,int);
           89  +int sqlite3PagerOpen(
           90  +  sqlite3_vfs*,
           91  +  Pager **ppPager,
           92  +  const char*,
           93  +  int,
           94  +  int,
           95  +  int,
           96  +  void(*)(DbPage*)
           97  +);
    90     98   int sqlite3PagerClose(Pager *pPager);
    91     99   int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
    92    100   
    93    101   /* Functions used to configure a Pager object. */
    94    102   void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
    95         -void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*));
    96    103   int sqlite3PagerSetPagesize(Pager*, u16*, int);
    97    104   int sqlite3PagerMaxPageCount(Pager*, int);
    98    105   void sqlite3PagerSetCachesize(Pager*, int);
    99    106   void sqlite3PagerSetSafetyLevel(Pager*,int,int);
   100    107   int sqlite3PagerLockingMode(Pager *, int);
   101    108   int sqlite3PagerJournalMode(Pager *, int);
   102    109   i64 sqlite3PagerJournalSizeLimit(Pager *, i64);

Changes to src/test2.c.

     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** Code for testing the pager.c module in SQLite.  This code
    13     13   ** is not included in the SQLite library.  It is used for automated
    14     14   ** testing of the SQLite library.
    15     15   **
    16         -** $Id: test2.c,v 1.73 2009/07/21 19:25:24 danielk1977 Exp $
           16  +** $Id: test2.c,v 1.74 2009/07/24 19:01:20 drh Exp $
    17     17   */
    18     18   #include "sqliteInt.h"
    19     19   #include "tcl.h"
    20     20   #include <stdlib.h>
    21     21   #include <string.h>
    22     22   #include <ctype.h>
    23     23   
................................................................................
    51     51     return zName;
    52     52   }
    53     53   
    54     54   /*
    55     55   ** Page size and reserved size used for testing.
    56     56   */
    57     57   static int test_pagesize = 1024;
           58  +
           59  +/*
           60  +** Dummy page reinitializer
           61  +*/
           62  +static void pager_test_reiniter(DbPage *pNotUsed){
           63  +  return;
           64  +}
    58     65   
    59     66   /*
    60     67   ** Usage:   pager_open FILENAME N-PAGE
    61     68   **
    62     69   ** Open a new pager
    63     70   */
    64     71   static int pager_open(
................................................................................
    75     82     if( argc!=3 ){
    76     83       Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
    77     84          " FILENAME N-PAGE\"", 0);
    78     85       return TCL_ERROR;
    79     86     }
    80     87     if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
    81     88     rc = sqlite3PagerOpen(sqlite3_vfs_find(0), &pPager, argv[1], 0, 0,
    82         -      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
           89  +      SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB,
           90  +      pager_test_reiniter);
    83     91     if( rc!=SQLITE_OK ){
    84     92       Tcl_AppendResult(interp, errorName(rc), 0);
    85     93       return TCL_ERROR;
    86     94     }
    87     95     sqlite3PagerSetCachesize(pPager, nPage);
    88     96     pageSize = test_pagesize;
    89     97     sqlite3PagerSetPagesize(pPager, &pageSize, -1);