/ Check-in [07b56965]
Login

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

Overview
Comment:Discard the contents of the pager-cache only when the change-counter indicates that it is stale. (CVS 3711)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:07b56965f3227c9f78680728b955395295c4aa49
User & Date: danielk1977 2007-03-23 18:12:07
Context
2007-03-24
16:45
Changes for exclusive access mode. There are still some bugs. (CVS 3712) check-in: b6c70037 user: danielk1977 tags: trunk
2007-03-23
18:12
Discard the contents of the pager-cache only when the change-counter indicates that it is stale. (CVS 3711) check-in: 07b56965 user: danielk1977 tags: trunk
10:08
Add a comment to the OsSectorSize() function. (CVS 3710) check-in: 0fd9983a user: danielk1977 tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace 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.292 2007/03/19 17:44:27 danielk1977 Exp $
           21  +** @(#) $Id: pager.c,v 1.293 2007/03/23 18:12:07 danielk1977 Exp $
    22     22   */
    23     23   #ifndef SQLITE_OMIT_DISKIO
    24     24   #include "sqliteInt.h"
    25     25   #include "os.h"
    26     26   #include "pager.h"
    27     27   #include <assert.h>
    28     28   #include <string.h>
................................................................................
   281    281     void *pCodecArg;            /* First argument to xCodec() */
   282    282     int nHash;                  /* Size of the pager hash table */
   283    283     PgHdr **aHash;              /* Hash table to map page number to PgHdr */
   284    284   #ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
   285    285     Pager *pNext;               /* Linked list of pagers in this thread */
   286    286   #endif
   287    287     char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
   288         -  int doNotSync;
          288  +  int doNotSync;              /* While true, do not spill the cache */
          289  +  u32 iChangeCount;           /* Db change-counter for which cache is valid */
   289    290   };
   290    291   
   291    292   /*
   292    293   ** If SQLITE_TEST is defined then increment the variable given in
   293    294   ** the argument
   294    295   */
   295    296   #ifdef SQLITE_TEST
................................................................................
   847    848       p = p->pNextHash;
   848    849     }
   849    850     return p;
   850    851   }
   851    852   
   852    853   /*
   853    854   ** Unlock the database file.
   854         -**
   855         -** Once all locks have been removed from the database file, other
   856         -** processes or threads might change the file.  So make sure all of
   857         -** our internal cache is invalidated.
   858    855   */
   859    856   static void pager_unlock(Pager *pPager){
   860    857     if( !MEMDB ){
   861    858       sqlite3OsUnlock(pPager->fd, NO_LOCK);
   862    859       pPager->dbSize = -1;
   863    860       IOTRACE(("UNLOCK %p\n", pPager))
   864    861     }
   865    862     pPager->state = PAGER_UNLOCK;
   866         -  assert( pPager->pAll==0 );
          863  +}
          864  +
          865  +/*
          866  +** Execute a rollback if a transaction is active and unlock the 
          867  +** database file. This is a no-op if the pager has already entered
          868  +** the error-state.
          869  +*/
          870  +static void pagerUnlockAndRollback(Pager *pPager){
          871  +  if( pPager->errCode ) return;
          872  +  if( pPager->state>=PAGER_RESERVED ){
          873  +    sqlite3PagerRollback(pPager);
          874  +  }
          875  +  pager_unlock(pPager);
          876  +  assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
   867    877   }
   868    878   
   869    879   
   870    880   /*
   871    881   ** Unlock the database and clear the in-memory cache.  This routine
   872    882   ** sets the state of the pager back to what it was when it was first
   873    883   ** opened.  Any outstanding pages are invalidated and subsequent attempts
................................................................................
   885    895     pPager->pFirstSynced = 0;
   886    896     pPager->pLast = 0;
   887    897     pPager->pAll = 0;
   888    898     pPager->nHash = 0;
   889    899     sqliteFree(pPager->aHash);
   890    900     pPager->nPage = 0;
   891    901     pPager->aHash = 0;
   892         -  if( pPager->state>=PAGER_RESERVED ){
   893         -    sqlite3PagerRollback(pPager);
   894         -  }
   895         -  pager_unlock(pPager);
   896    902     pPager->nRef = 0;
   897         -  assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
          903  +}
          904  +
          905  +/*
          906  +** This function resets the various pager flags to their initial
          907  +** state but does not discard the cached content.
          908  +*/
          909  +static void pagerSoftReset(Pager *pPager){
          910  +  PgHdr *pPg;
          911  +
          912  +  assert(pPager->pStmt==0);
          913  +  assert(pPager->nRef==0);
          914  +  assert(pPager->pFirstSynced==pPager->pFirst);
          915  +  assert(pPager->aInJournal==0);
          916  +
          917  +  for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
          918  +    assert( pPg->nRef==0 );
          919  +    pPg->inJournal = 0;
          920  +    pPg->inStmt = 0;
          921  +    pPg->dirty = 0;
          922  +    pPg->needSync = 0;
          923  +    pPg->alwaysRollback = 0;
          924  +  }
   898    925   }
   899    926   
   900    927   /*
   901    928   ** When this routine is called, the pager has the journal file open and
   902    929   ** a RESERVED or EXCLUSIVE lock on the database.  This routine releases
   903    930   ** the database lock and acquires a SHARED lock in its place.  The journal
   904    931   ** file is deleted and closed.
................................................................................
  1274   1301   ** back (or no pages if the journal header is corrupted). The journal file
  1275   1302   ** is then deleted and SQLITE_OK returned, just as if no corruption had
  1276   1303   ** been encountered.
  1277   1304   **
  1278   1305   ** If an I/O or malloc() error occurs, the journal-file is not deleted
  1279   1306   ** and an error code is returned.
  1280   1307   */
  1281         -static int pager_playback(Pager *pPager){
         1308  +static int pager_playback(Pager *pPager, int isHot){
  1282   1309     i64 szJ;                 /* Size of the journal file in bytes */
  1283   1310     u32 nRec;                /* Number of Records in the journal */
  1284   1311     int i;                   /* Loop counter */
  1285   1312     Pgno mxPg = 0;           /* Size of the original file in pages */
  1286   1313     int rc;                  /* Result code of a subroutine */
  1287   1314     char *zMaster = 0;       /* Name of master journal file if any */
  1288   1315   
................................................................................
  1333   1360       ** file consists of pages, there are no more journal headers. Compute
  1334   1361       ** the value of nRec based on this assumption.
  1335   1362       */
  1336   1363       if( nRec==0xffffffff ){
  1337   1364         assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) );
  1338   1365         nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager);
  1339   1366       }
         1367  +
         1368  +    /* If nRec is 0 and this rollback is of a transaction created by this
         1369  +    ** process. In this case the rest of the journal file consists of
         1370  +    ** journalled copies of pages that need to be read back into the cache.
         1371  +    */
         1372  +    if( nRec==0 && !isHot ){
         1373  +      nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager);
         1374  +    }
  1340   1375   
  1341   1376       /* If this is the first header read from the journal, truncate the
  1342   1377       ** database file back to it's original size.
  1343   1378       */
  1344   1379       if( pPager->state>=PAGER_EXCLUSIVE && 
  1345   1380           pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
  1346   1381         assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
................................................................................
  1357   1392         rc = pager_playback_one_page(pPager, pPager->jfd, 1);
  1358   1393         if( rc!=SQLITE_OK ){
  1359   1394           if( rc==SQLITE_DONE ){
  1360   1395             rc = SQLITE_OK;
  1361   1396             pPager->journalOff = szJ;
  1362   1397             break;
  1363   1398           }else{
  1364         -          /* If we are unable to rollback a hot journal, then the database
  1365         -          ** is probably not recoverable.  Return CORRUPT.
  1366         -          */
  1367         -          rc = SQLITE_CORRUPT;
  1368   1399             goto end_playback;
  1369   1400           }
  1370   1401         }
  1371   1402       }
  1372   1403     }
  1373   1404     /*NOTREACHED*/
  1374   1405     assert( 0 );
................................................................................
  2092   2123     assert( pPager );
  2093   2124     assert( pTsd && pTsd->nAlloc );
  2094   2125   #endif
  2095   2126   
  2096   2127     disable_simulated_io_errors();
  2097   2128     pPager->errCode = 0;
  2098   2129     pager_reset(pPager);
         2130  +  pagerUnlockAndRollback(pPager);
  2099   2131     enable_simulated_io_errors();
  2100   2132     TRACE2("CLOSE %d\n", PAGERID(pPager));
  2101   2133     IOTRACE(("CLOSE %p\n", pPager))
  2102   2134     assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
  2103   2135     if( pPager->journalOpen ){
  2104   2136       sqlite3OsClose(&pPager->jfd);
  2105   2137     }
................................................................................
  2610   2642         }
  2611   2643       }
  2612   2644     }
  2613   2645   
  2614   2646     return nReleased;
  2615   2647   }
  2616   2648   #endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
         2649  +
         2650  +/*
         2651  +** This function is called to obtain the shared lock required before
         2652  +** data may be read from the pager cache. If the shared lock has already
         2653  +** been obtained, this function is a no-op.
         2654  +*/
         2655  +static int pagerSharedLock(Pager *pPager){
         2656  +  int rc = SQLITE_OK;
         2657  +
         2658  +  if( pPager->state==PAGER_UNLOCK ){
         2659  +    if( !MEMDB ){
         2660  +      assert( pPager->nRef==0 );
         2661  +      if( !pPager->noReadlock ){
         2662  +        rc = pager_wait_on_lock(pPager, SHARED_LOCK);
         2663  +        if( rc!=SQLITE_OK ){
         2664  +          return pager_error(pPager, rc);
         2665  +        }
         2666  +        assert( pPager->state>=SHARED_LOCK );
         2667  +      }
         2668  +  
         2669  +      /* If a journal file exists, and there is no RESERVED lock on the
         2670  +      ** database file, then it either needs to be played back or deleted.
         2671  +      */
         2672  +      if( hasHotJournal(pPager) ){
         2673  +        /* Get an EXCLUSIVE lock on the database file. At this point it is
         2674  +        ** important that a RESERVED lock is not obtained on the way to the
         2675  +        ** EXCLUSIVE lock. If it were, another process might open the
         2676  +        ** database file, detect the RESERVED lock, and conclude that the
         2677  +        ** database is safe to read while this process is still rolling it 
         2678  +        ** back.
         2679  +        ** 
         2680  +        ** Because the intermediate RESERVED lock is not requested, the
         2681  +        ** second process will get to this point in the code and fail to
         2682  +        ** obtain it's own EXCLUSIVE lock on the database file.
         2683  +        */
         2684  +        rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
         2685  +        if( rc!=SQLITE_OK ){
         2686  +          pager_unlock(pPager);
         2687  +          return pager_error(pPager, rc);
         2688  +        }
         2689  +        pPager->state = PAGER_EXCLUSIVE;
         2690  + 
         2691  +        /* Open the journal for reading only.  Return SQLITE_BUSY if
         2692  +        ** we are unable to open the journal file. 
         2693  +        **
         2694  +        ** The journal file does not need to be locked itself.  The
         2695  +        ** journal file is never open unless the main database file holds
         2696  +        ** a write lock, so there is never any chance of two or more
         2697  +        ** processes opening the journal at the same time.
         2698  +        */
         2699  +        rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
         2700  +        if( rc!=SQLITE_OK ){
         2701  +          pager_unlock(pPager);
         2702  +          return SQLITE_BUSY;
         2703  +        }
         2704  +        pPager->journalOpen = 1;
         2705  +        pPager->journalStarted = 0;
         2706  +        pPager->journalOff = 0;
         2707  +        pPager->setMaster = 0;
         2708  +        pPager->journalHdr = 0;
         2709  + 
         2710  +        /* Playback and delete the journal.  Drop the database write
         2711  +        ** lock and reacquire the read lock.
         2712  +        */
         2713  +        rc = pager_playback(pPager, 1);
         2714  +        if( rc!=SQLITE_OK ){
         2715  +          return pager_error(pPager, rc);
         2716  +        }
         2717  +      }
         2718  +
         2719  +      if( pPager->pAll ){
         2720  +        PgHdr *pPage1 = pager_lookup(pPager, 1);
         2721  +        if( pPage1 ){
         2722  +          unlinkHashChain(pPager, pPage1);
         2723  +        }
         2724  +
         2725  +        assert( !pager_lookup(pPager, 1) );
         2726  +        rc = sqlite3PagerAcquire(pPager, 1, &pPage1, 0);
         2727  +        if( rc==SQLITE_OK ){
         2728  +	  /* The change-counter is stored at offset 24. See also
         2729  +          ** pager_incr_changecounter().
         2730  +          */
         2731  +          u32 iChangeCount = retrieve32bits(pPage1, 24);
         2732  +          pPager->nRef++;
         2733  +          sqlite3PagerUnref(pPage1);
         2734  +          pPager->nRef--;
         2735  +          if( iChangeCount!=pPager->iChangeCount ){
         2736  +            pager_reset(pPager);
         2737  +          }else{
         2738  +            pagerSoftReset(pPager);
         2739  +          }
         2740  +          pPager->iChangeCount = iChangeCount;
         2741  +        }
         2742  +      }
         2743  +    }
         2744  +    pPager->state = PAGER_SHARED;
         2745  +  }
         2746  +
         2747  +  return rc;
         2748  +}
  2617   2749   
  2618   2750   /*
  2619   2751   ** Acquire a page.
  2620   2752   **
  2621   2753   ** A read lock on the disk file is obtained when the first page is acquired. 
  2622   2754   ** This read lock is dropped when the last page is released.
  2623   2755   **
................................................................................
  2643   2775   ** rewritten without first being read so there is no point it doing
  2644   2776   ** the disk I/O.
  2645   2777   */
  2646   2778   int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag){
  2647   2779     PgHdr *pPg;
  2648   2780     int rc;
  2649   2781   
         2782  +  assert( pPager->state==PAGER_UNLOCK || pPager->nRef>0 || pgno==1 );
         2783  +
  2650   2784     /* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
  2651   2785     ** number greater than this, or zero, is requested.
  2652   2786     */
  2653   2787     if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
  2654   2788       return SQLITE_CORRUPT_BKPT;
  2655   2789     }
  2656   2790   
................................................................................
  2661   2795     if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
  2662   2796       return pPager->errCode;
  2663   2797     }
  2664   2798   
  2665   2799     /* If this is the first page accessed, then get a SHARED lock
  2666   2800     ** on the database file.
  2667   2801     */
  2668         -  if( pPager->nRef==0 && !MEMDB ){
  2669         -    if( !pPager->noReadlock ){
  2670         -      rc = pager_wait_on_lock(pPager, SHARED_LOCK);
  2671         -      if( rc!=SQLITE_OK ){
  2672         -        return pager_error(pPager, rc);
  2673         -      }
  2674         -    }
  2675         -
  2676         -    /* If a journal file exists, and there is no RESERVED lock on the
  2677         -    ** database file, then it either needs to be played back or deleted.
  2678         -    */
  2679         -    if( hasHotJournal(pPager) ){
  2680         -       /* Get an EXCLUSIVE lock on the database file. At this point it is
  2681         -       ** important that a RESERVED lock is not obtained on the way to the
  2682         -       ** EXCLUSIVE lock. If it were, another process might open the
  2683         -       ** database file, detect the RESERVED lock, and conclude that the
  2684         -       ** database is safe to read while this process is still rolling it 
  2685         -       ** back.
  2686         -       ** 
  2687         -       ** Because the intermediate RESERVED lock is not requested, the
  2688         -       ** second process will get to this point in the code and fail to
  2689         -       ** obtain it's own EXCLUSIVE lock on the database file.
  2690         -       */
  2691         -       rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
  2692         -       if( rc!=SQLITE_OK ){
  2693         -         pager_unlock(pPager);
  2694         -         return pager_error(pPager, rc);
  2695         -       }
  2696         -       pPager->state = PAGER_EXCLUSIVE;
  2697         -
  2698         -       /* Open the journal for reading only.  Return SQLITE_BUSY if
  2699         -       ** we are unable to open the journal file. 
  2700         -       **
  2701         -       ** The journal file does not need to be locked itself.  The
  2702         -       ** journal file is never open unless the main database file holds
  2703         -       ** a write lock, so there is never any chance of two or more
  2704         -       ** processes opening the journal at the same time.
  2705         -       */
  2706         -       rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
  2707         -       if( rc!=SQLITE_OK ){
  2708         -         pager_unlock(pPager);
  2709         -         return SQLITE_BUSY;
  2710         -       }
  2711         -       pPager->journalOpen = 1;
  2712         -       pPager->journalStarted = 0;
  2713         -       pPager->journalOff = 0;
  2714         -       pPager->setMaster = 0;
  2715         -       pPager->journalHdr = 0;
  2716         -
  2717         -       /* Playback and delete the journal.  Drop the database write
  2718         -       ** lock and reacquire the read lock.
  2719         -       */
  2720         -       rc = pager_playback(pPager);
  2721         -       if( rc!=SQLITE_OK ){
  2722         -         return pager_error(pPager, rc);
  2723         -       }
  2724         -    }
  2725         -    pPg = 0;
  2726         -  }else{
  2727         -    /* Search for page in cache */
  2728         -    pPg = pager_lookup(pPager, pgno);
  2729         -    if( MEMDB && pPager->state==PAGER_UNLOCK ){
  2730         -      pPager->state = PAGER_SHARED;
  2731         -    }
  2732         -  }
         2802  +  rc = pagerSharedLock(pPager);
         2803  +  if( rc!=SQLITE_OK ){
         2804  +    return rc;
         2805  +  }
         2806  +  assert( pPager->state!=PAGER_UNLOCK );
         2807  +
         2808  +  pPg = pager_lookup(pPager, pgno);
  2733   2809     if( pPg==0 ){
  2734   2810       /* The requested page is not in the page cache. */
  2735   2811       int h;
  2736   2812       TEST_INCR(pPager->nMiss);
  2737   2813       if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ||
  2738   2814           (pPager->pFirstSynced==0 && pPager->doNotSync)
  2739   2815       ){
................................................................................
  2764   2840           pPager->nMaxPage++;
  2765   2841         }
  2766   2842       }else{
  2767   2843         rc = pager_recycle(pPager, 1, &pPg);
  2768   2844         if( rc!=SQLITE_OK ){
  2769   2845           return rc;
  2770   2846         }
  2771         -      assert(pPg) ;
         2847  +      assert( pPager->state>=SHARED_LOCK );
         2848  +      assert(pPg);
  2772   2849       }
  2773   2850       pPg->pgno = pgno;
  2774   2851       if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
  2775   2852         sqlite3CheckMemory(pPager->aInJournal, pgno/8);
  2776   2853         assert( pPager->journalOpen );
  2777   2854         pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
  2778   2855         pPg->needSync = 0;
................................................................................
  2837   2914       }
  2838   2915   
  2839   2916   #ifdef SQLITE_CHECK_PAGES
  2840   2917       pPg->pageHash = pager_pagehash(pPg);
  2841   2918   #endif
  2842   2919     }else{
  2843   2920       /* The requested page is in the page cache. */
         2921  +    assert(pPager->nRef>0 || pgno==1);
  2844   2922       TEST_INCR(pPager->nHit);
  2845   2923       page_ref(pPg);
  2846   2924     }
  2847   2925     *ppPage = pPg;
  2848   2926     return SQLITE_OK;
  2849   2927   }
  2850   2928   
................................................................................
  2860   2938   ** has ever happened.
  2861   2939   */
  2862   2940   DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
  2863   2941     PgHdr *pPg;
  2864   2942   
  2865   2943     assert( pPager!=0 );
  2866   2944     assert( pgno!=0 );
  2867         -  if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
         2945  +
         2946  +  if( pPager->state==PAGER_UNLOCK ){
         2947  +    return 0;
         2948  +  }
         2949  +  if( (pPager->errCode && pPager->errCode!=SQLITE_FULL) ){
  2868   2950       return 0;
  2869   2951     }
  2870   2952     pPg = pager_lookup(pPager, pgno);
  2871   2953     if( pPg==0 ) return 0;
  2872   2954     page_ref(pPg);
  2873   2955     return pPg;
  2874   2956   }
................................................................................
  2913   2995       }
  2914   2996     
  2915   2997       /* When all pages reach the freelist, drop the read lock from
  2916   2998       ** the database file.
  2917   2999       */
  2918   3000       pPager->nRef--;
  2919   3001       assert( pPager->nRef>=0 );
  2920         -    if( pPager->nRef==0 && !MEMDB ){
  2921         -      pager_reset(pPager);
         3002  +    if( pPager->nRef==0 ){
         3003  +      /* pager_reset(pPager); */
         3004  +      pagerUnlockAndRollback(pPager);
  2922   3005       }
  2923   3006     }
  2924   3007     return SQLITE_OK;
  2925   3008   }
  2926   3009   
  2927   3010   /*
  2928   3011   ** Create a journal file for pPager.  There should already be a RESERVED
................................................................................
  3560   3643     if( !pPager->dirtyCache || !pPager->journalOpen ){
  3561   3644       rc = pager_unwritelock(pPager);
  3562   3645       return rc;
  3563   3646     }
  3564   3647   
  3565   3648     if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
  3566   3649       if( pPager->state>=PAGER_EXCLUSIVE ){
  3567         -      pager_playback(pPager);
         3650  +      pager_playback(pPager, 0);
  3568   3651       }
  3569   3652       return pPager->errCode;
  3570   3653     }
  3571   3654     if( pPager->state==PAGER_RESERVED ){
  3572   3655       int rc2;
  3573         -    rc = pager_reload_cache(pPager);
         3656  +    /* rc = pager_reload_cache(pPager); */
         3657  +    rc = pager_playback(pPager, 0);
  3574   3658       rc2 = pager_unwritelock(pPager);
  3575   3659       if( rc==SQLITE_OK ){
  3576   3660         rc = rc2;
  3577   3661       }
  3578   3662     }else{
  3579         -    rc = pager_playback(pPager);
         3663  +    rc = pager_playback(pPager, 0);
  3580   3664     }
  3581   3665     pPager->dbSize = -1;
  3582   3666   
  3583   3667     /* If an error occurs during a ROLLBACK, we can no longer trust the pager
  3584   3668     ** cache. So call pager_error() on the way out to make any error 
  3585   3669     ** persistent.
  3586   3670     */
................................................................................
  3798   3882   
  3799   3883     /* Read the current value at byte 24. */
  3800   3884     change_counter = retrieve32bits(pPgHdr, 24);
  3801   3885   
  3802   3886     /* Increment the value just read and write it back to byte 24. */
  3803   3887     change_counter++;
  3804   3888     put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
         3889  +  pPager->iChangeCount = change_counter;
  3805   3890   
  3806   3891     /* Release the page reference. */
  3807   3892     sqlite3PagerUnref(pPgHdr);
  3808   3893     return SQLITE_OK;
  3809   3894   }
  3810   3895   
  3811   3896   /*

Changes to test/pager.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this script is page cache subsystem.
    13     13   #
    14         -# $Id: pager.test,v 1.25 2006/01/23 15:25:48 danielk1977 Exp $
           14  +# $Id: pager.test,v 1.26 2007/03/23 18:12:07 danielk1977 Exp $
    15     15   
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   if {[info commands pager_open]!=""} {
    21     21   db close
................................................................................
    99     99   } {1}
   100    100   do_test pager-2.8 {
   101    101     page_read $::g1
   102    102   } {}
   103    103   do_test pager-2.9 {
   104    104     page_unref $::g1
   105    105   } {}
          106  +
          107  +# Update 24/03/2007: Even though the ref-count has dropped to zero, the
          108  +# pager-cache still contains some pages. Previously, it was always true
          109  +# that if there were no references to a pager it was empty.
   106    110   do_test pager-2.10 {
   107    111     pager_stats $::p1
   108         -} {ref 0 page 0 max 10 size -1 state 0 err 0 hit 0 miss 1 ovfl 0}
          112  +} {ref 0 page 1 max 10 size -1 state 0 err 0 hit 0 miss 1 ovfl 0}
   109    113   do_test pager-2.11 {
   110    114     set ::g1 [page_get $::p1 1]
   111    115     expr {$::g1!=0}
   112    116   } {1}
   113    117   do_test pager-2.12 {
   114    118     page_number $::g1
   115    119   } {1}
   116    120   do_test pager-2.13 {
   117    121     pager_stats $::p1
   118         -} {ref 1 page 1 max 10 size 0 state 1 err 0 hit 0 miss 2 ovfl 0}
          122  +} {ref 1 page 2 max 10 size 0 state 1 err 0 hit 1 miss 2 ovfl 0}
   119    123   do_test pager-2.14 {
   120    124     set v [catch {
   121    125       page_write $::g1 "Page-One"
   122    126     } msg]
   123    127     lappend v $msg
   124    128   } {0 {}}
   125    129   do_test pager-2.15 {
   126    130     pager_stats $::p1
   127         -} {ref 1 page 1 max 10 size 1 state 2 err 0 hit 0 miss 2 ovfl 0}
          131  +} {ref 1 page 2 max 10 size 1 state 2 err 0 hit 1 miss 2 ovfl 0}
   128    132   do_test pager-2.16 {
   129    133     page_read $::g1
   130    134   } {Page-One}
   131    135   do_test pager-2.17 {
   132    136     set v [catch {
   133    137       pager_commit $::p1
   134    138     } msg]
   135    139     lappend v $msg
   136    140   } {0 {}}
   137    141   do_test pager-2.20 {
   138    142     pager_stats $::p1
   139         -} {ref 1 page 1 max 10 size -1 state 1 err 0 hit 1 miss 2 ovfl 0}
          143  +} {ref 1 page 2 max 10 size -1 state 1 err 0 hit 2 miss 2 ovfl 0}
   140    144   do_test pager-2.19 {
   141    145     pager_pagecount $::p1
   142    146   } {1}
   143    147   do_test pager-2.21 {
   144    148     pager_stats $::p1
   145         -} {ref 1 page 1 max 10 size 1 state 1 err 0 hit 1 miss 2 ovfl 0}
          149  +} {ref 1 page 2 max 10 size 1 state 1 err 0 hit 2 miss 2 ovfl 0}
   146    150   do_test pager-2.22 {
   147    151     page_unref $::g1
   148    152   } {}
   149    153   do_test pager-2.23 {
   150    154     pager_stats $::p1
   151         -} {ref 0 page 0 max 10 size -1 state 0 err 0 hit 1 miss 2 ovfl 0}
          155  +} {ref 0 page 2 max 10 size -1 state 0 err 0 hit 2 miss 2 ovfl 0}
   152    156   do_test pager-2.24 {
   153    157     set v [catch {
   154    158       page_get $::p1 1
   155    159     } ::g1]
   156    160     if {$v} {lappend v $::g1}
   157    161     set v
   158    162   } {0}
................................................................................
   408    412       set ::p2 [pager_open :memory: 10]
   409    413       pager_truncate $::p2 5
   410    414     } {}
   411    415     do_test pager-4.6.3 {
   412    416       for {set i 1} {$i<5} {incr i} {
   413    417         set p [page_get $::p2 $i]
   414    418         page_write $p "Page $i"
   415         -      page_unref $p
   416    419         pager_commit $::p2
          420  +      page_unref $p
   417    421       }
   418         -    pager_truncate $::p2 3
          422  +    # pager_truncate $::p2 3
   419    423     } {}
   420    424     do_test pager-4.6.4 {
   421    425       pager_close $::p2
   422    426     } {}
   423    427   }
   424    428   
   425    429   do_test pager-4.99 {

Changes to test/pager2.test.

     7      7   #    May you find forgiveness for yourself and forgive others.
     8      8   #    May you share freely, never taking more than you give.
     9      9   #
    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this script is page cache subsystem.
    13     13   #
    14         -# $Id: pager2.test,v 1.5 2004/11/22 05:26:28 danielk1977 Exp $
           14  +# $Id: pager2.test,v 1.6 2007/03/23 18:12:07 danielk1977 Exp $
    15     15   
    16     16   
    17     17   set testdir [file dirname $argv0]
    18     18   source $testdir/tester.tcl
    19     19   
    20     20   # Don't run this test file if the pager test interface [pager_open] is not
    21     21   # available, or the library was compiled without in-memory database support.
................................................................................
   103    103     page_read $::g1
   104    104   } {}
   105    105   do_test pager2-2.9 {
   106    106     page_unref $::g1
   107    107   } {}
   108    108   do_test pager2-2.10 {
   109    109     pager_stats $::p1
   110         -} {ref 0 page 1 max 10 size 0 state 1 err 0 hit 0 miss 1 ovfl 0}
          110  +} {ref 0 page 1 max 10 size 0 state 0 err 0 hit 0 miss 1 ovfl 0}
   111    111   do_test pager2-2.11 {
   112    112     set ::g1 [page_get $::p1 1]
   113    113     expr {$::g1!=0}
   114    114   } {1}
   115    115   do_test pager2-2.12 {
   116    116     page_number $::g1
   117    117   } {1}
................................................................................
   146    146     pager_stats $::p1
   147    147   } {ref 1 page 1 max 10 size 1 state 1 err 0 hit 1 miss 1 ovfl 0}
   148    148   do_test pager2-2.22 {
   149    149     page_unref $::g1
   150    150   } {}
   151    151   do_test pager2-2.23 {
   152    152     pager_stats $::p1
   153         -} {ref 0 page 1 max 10 size 1 state 1 err 0 hit 1 miss 1 ovfl 0}
          153  +} {ref 0 page 1 max 10 size 1 state 0 err 0 hit 1 miss 1 ovfl 0}
   154    154   do_test pager2-2.24 {
   155    155     set v [catch {
   156    156       page_get $::p1 1
   157    157     } ::g1]
   158    158     if {$v} {lappend v $::g1}
   159    159     set v
   160    160   } {0}