/ Check-in [719c1b79]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Auto-vacuum bug: Correctly manipulate page cache hash-table entries in sqlite3pager_movepage(). (CVS 2046)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 719c1b79671c8cd7c5a6b5967ad4265b65e433d3
User & Date: danielk1977 2004-11-03 08:44:06
Context
2004-11-03
09:30
Comment the autovacuum.test script. No code or test-case changes. (CVS 2047) check-in: 2eacd386 user: danielk1977 tags: trunk
08:44
Auto-vacuum bug: Correctly manipulate page cache hash-table entries in sqlite3pager_movepage(). (CVS 2046) check-in: 719c1b79 user: danielk1977 tags: trunk
03:59
The makefile now runs mkkeywordhash.c. Keywords that are unused are omitted from the keyword hash table. (CVS 2045) check-in: 007aec11 user: drh 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.170 2004/11/02 12:56:41 danielk1977 Exp $
           21  +** @(#) $Id: pager.c,v 1.171 2004/11/03 08:44:06 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   
................................................................................
  1630   1630   }
  1631   1631   
  1632   1632   /*
  1633   1633   ** Forward declaration
  1634   1634   */
  1635   1635   static int syncJournal(Pager*);
  1636   1636   
         1637  +
         1638  +/*
         1639  +** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate
         1640  +** that the page is not part of any hash chain. This is required because the
         1641  +** sqlite3pager_movepage() routine can leave a page in the 
         1642  +** pNextFree/pPrevFree list that is not a part of any hash-chain.
         1643  +*/
         1644  +static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
         1645  +  if( pPg->pgno==0 ){
         1646  +    /* If the page number is zero, then this page is not in any hash chain. */
         1647  +    return;
         1648  +  }
         1649  +  if( pPg->pNextHash ){
         1650  +    pPg->pNextHash->pPrevHash = pPg->pPrevHash;
         1651  +  }
         1652  +  if( pPg->pPrevHash ){
         1653  +    assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg );
         1654  +    pPg->pPrevHash->pNextHash = pPg->pNextHash;
         1655  +  }else{
         1656  +    int h = pager_hash(pPg->pgno);
         1657  +    assert( pPager->aHash[h]==pPg );
         1658  +    pPager->aHash[h] = pPg->pNextHash;
         1659  +  }
         1660  +
         1661  +  pPg->pgno = 0;
         1662  +  pPg->pNextHash = pPg->pPrevHash = 0;
         1663  +}
  1637   1664   
  1638   1665   /*
  1639   1666   ** Unlink a page from the free list (the list of all pages where nRef==0)
  1640   1667   ** and from its hash collision chain.
  1641   1668   */
  1642   1669   static void unlinkPage(PgHdr *pPg){
  1643   1670     Pager *pPager = pPg->pPager;
................................................................................
  1661   1688     }else{
  1662   1689       assert( pPager->pLast==pPg );
  1663   1690       pPager->pLast = pPg->pPrevFree;
  1664   1691     }
  1665   1692     pPg->pNextFree = pPg->pPrevFree = 0;
  1666   1693   
  1667   1694     /* Unlink from the pgno hash table */
         1695  +  unlinkHashChain(pPager, pPg);
         1696  +/*
  1668   1697     if( pPg->pNextHash ){
  1669   1698       pPg->pNextHash->pPrevHash = pPg->pPrevHash;
  1670   1699     }
  1671   1700     if( pPg->pPrevHash ){
  1672   1701       pPg->pPrevHash->pNextHash = pPg->pNextHash;
  1673   1702     }else{
  1674   1703       int h = pager_hash(pPg->pgno);
  1675   1704       assert( pPager->aHash[h]==pPg );
  1676   1705       pPager->aHash[h] = pPg->pNextHash;
  1677   1706     }
  1678   1707     pPg->pNextHash = pPg->pPrevHash = 0;
         1708  +*/
  1679   1709   }
  1680   1710   
  1681   1711   /*
  1682   1712   ** This routine is used to truncate an in-memory database.  Delete
  1683   1713   ** all pages whose pgno is larger than pPager->dbSize and is unreferenced.
  1684   1714   ** Referenced pages larger than pPager->dbSize are zeroed.
  1685   1715   */
................................................................................
  3211   3241     }
  3212   3242   
  3213   3243   sync_exit:
  3214   3244     return rc;
  3215   3245   }
  3216   3246   
  3217   3247   #ifndef SQLITE_OMIT_AUTOVACUUM
         3248  +
  3218   3249   /*
  3219   3250   ** Move the page identified by pData to location pgno in the file. 
  3220   3251   **
  3221   3252   ** There must be no references to the current page pgno. If current page
  3222   3253   ** pgno is not already in the rollback journal, it is not written there by
  3223   3254   ** by this routine. The same applies to the page pData refers to on entry to
  3224   3255   ** this routine.
................................................................................
  3229   3260   **
  3230   3261   ** A transaction must be active when this routine is called, however it is 
  3231   3262   ** illegal to call this routine if a statment transaction is active.
  3232   3263   */
  3233   3264   int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
  3234   3265     PgHdr *pPg = DATA_TO_PGHDR(pData);
  3235   3266     PgHdr *pPgOld; 
         3267  +  int h;
  3236   3268   
  3237   3269     assert( !pPager->stmtInUse );
  3238         -  /* assert( pPg->pNextFree==0 && pPg->pPrevFree==0 && pPg->nRef>0 ); */
  3239   3270     assert( pPg->nRef>0 );
  3240   3271   
  3241   3272     /* Unlink pPg from it's hash-chain */
  3242         -  if( pPg->pNextHash ){
  3243         -    pPg->pNextHash->pPrevHash = pPg->pPrevHash;
  3244         -  }
  3245         -  if( pPg->pPrevHash ){
  3246         -    pPg->pPrevHash->pNextHash = pPg->pNextHash;
  3247         -  }else{
  3248         -    int h = pager_hash(pPg->pgno);
  3249         -    assert( pPager->aHash[h]==pPg );
  3250         -    pPager->aHash[h] = pPg->pNextHash;
         3273  +  unlinkHashChain(pPager, pPg);
         3274  +
         3275  +  /* If the cache contains a page with page-number pgno exists, remove it
         3276  +  ** from it's hash chain.
         3277  +  */
         3278  +  pPgOld = pager_lookup(pPager, pgno);
         3279  +  if( pPgOld ){
         3280  +    assert( pPgOld->nRef==0 );
         3281  +    unlinkHashChain(pPager, pPgOld);
         3282  +    pPgOld->dirty = 0;
  3251   3283     }
  3252   3284   
  3253         -  /* Change the page number for pPg */
         3285  +  /* Change the page number for pPg and insert it into the new hash-chain. */
  3254   3286     pPg->pgno = pgno;
  3255         -
  3256         -  pPgOld = pager_lookup(pPager, pgno);
  3257         -  if( pPgOld ){
  3258         -    /* Remove pPgOld from the page number hash-chain and insert pPg. */
  3259         -    assert(pPgOld->nRef==0 && !pPgOld->pNextStmt && !pPgOld->pPrevStmt );
  3260         -    if( pPgOld->pNextHash ){
  3261         -      pPgOld->pNextHash->pPrevHash = pPg;
  3262         -    }
  3263         -    if( pPgOld->pPrevHash ){
  3264         -      pPgOld->pPrevHash->pNextHash = pPg;
  3265         -    }else{
  3266         -      int h = pager_hash(pgno);
  3267         -      assert( pPager->aHash[h]==pPgOld );
  3268         -      pPager->aHash[h] = pPg;
  3269         -    }
  3270         -    pPgOld->pNextHash = pPgOld->pPrevHash = 0;
  3271         -  }else{
  3272         -    /* Insert pPg into it's new hash-chain. */
  3273         -    int h = pager_hash(pgno);
  3274         -    if( pPager->aHash[h] ){
  3275         -      pPager->aHash[h]->pNextHash = pPg;
  3276         -    }
  3277         -    pPg->pNextHash = pPager->aHash[h];
  3278         -    pPg->pPrevHash = 0;
         3287  +  h = pager_hash(pgno);
         3288  +  if( pPager->aHash[h] ){
         3289  +    assert( pPager->aHash[h]->pPrevHash==0 );
         3290  +    pPager->aHash[h]->pPrevHash = pPg;
  3279   3291     }
         3292  +  pPg->pNextHash = pPager->aHash[h];
         3293  +  pPager->aHash[h] = pPg;
         3294  +  pPg->pPrevHash = 0;
  3280   3295   
  3281         -  /* Don't write the old page when sqlite3pager_sync() is called. Do write
  3282         -  ** the new one. 
  3283         -  */
  3284         -  pPgOld->dirty = 0;
  3285   3296     pPg->dirty = 1;
  3286   3297     pPager->dirtyCache = 1;
  3287   3298   
  3288   3299     return SQLITE_OK;
  3289   3300   }
  3290   3301   #endif
  3291   3302