/ Check-in [555351dd]
Login

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

Overview
Comment::-) (CVS 208)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 555351dd1918f96167e2cb46cc1db6496e8d10a3
User & Date: drh 2001-04-11 14:29:22
Context
2001-04-12
23:21
More testing (CVS 209) check-in: 3bde1284 user: drh tags: trunk
2001-04-11
14:29
:-) (CVS 208) check-in: 555351dd user: drh tags: trunk
14:28
better handling of out-of-memory errors (CVS 207) check-in: 86b30cd0 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Added src/pager.c.

            1  +/*
            2  +** Copyright (c) 2001 D. Richard Hipp
            3  +**
            4  +** This program is free software; you can redistribute it and/or
            5  +** modify it under the terms of the GNU General Public
            6  +** License as published by the Free Software Foundation; either
            7  +** version 2 of the License, or (at your option) any later version.
            8  +**
            9  +** This program is distributed in the hope that it will be useful,
           10  +** but WITHOUT ANY WARRANTY; without even the implied warranty of
           11  +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
           12  +** General Public License for more details.
           13  +** 
           14  +** You should have received a copy of the GNU General Public
           15  +** License along with this library; if not, write to the
           16  +** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
           17  +** Boston, MA  02111-1307, USA.
           18  +**
           19  +** Author contact information:
           20  +**   drh@hwaci.com
           21  +**   http://www.hwaci.com/drh/
           22  +**
           23  +*************************************************************************
           24  +** This is the implementation of the page cache subsystem.
           25  +** 
           26  +** The page cache is used to access a database file.  The pager journals
           27  +** all writes in order to support rollback.  Locking is used to limit
           28  +** access to one or more reader or on writer.
           29  +**
           30  +** @(#) $Id: pager.c,v 1.1 2001/04/11 14:29:22 drh Exp $
           31  +*/
           32  +#include "pager.h"
           33  +#include <fcntl.h>
           34  +#include <sys/stat.h>
           35  +#include <unistd.h>
           36  +#include <assert.h>
           37  +
           38  +/*
           39  +** The page cache as a whole is always in one of the following
           40  +** states:
           41  +**
           42  +**   SQLITE_UNLOCK       The page cache is not currently reading or 
           43  +**                       writing the database file.  There is no
           44  +**                       data held in memory.  This is the initial
           45  +**                       state.
           46  +**
           47  +**   SQLITE_READLOCK     The page cache is reading the database.
           48  +**                       Writing is not permitted.  There can be
           49  +**                       multiple readers accessing the same database
           50  +**                       at the same time.
           51  +**
           52  +**   SQLITE_WRITELOCK    The page cache is writing the database.
           53  +**                       Access is exclusive.  No other processes or
           54  +**                       threads can be reading or writing while one
           55  +**                       process is writing.
           56  +**
           57  +** The page cache comes up in PCS_UNLOCK.  The first time a
           58  +** sqlite_page_get() occurs, the state transitions to PCS_READLOCK.
           59  +** After all pages have been released using sqlite_page_unref(),
           60  +** the state transitions back to PCS_UNLOCK.  The first time
           61  +** that sqlite_page_write() is called, the state transitions to
           62  +** PCS_WRITELOCK.  The sqlite_page_rollback() and sqlite_page_commit()
           63  +** functions transition the state back to PCS_READLOCK.
           64  +*/
           65  +#define SQLITE_UNLOCK      0
           66  +#define SQLITE_READLOCK    1
           67  +#define SQLITE_WRITELOCK   2
           68  +
           69  +/*
           70  +** Each in-memory image of a page begins with the following header.
           71  +*/
           72  +struct PgHdr {
           73  +  Pager *pPager;                 /* The pager to which this page belongs */
           74  +  Pgno pgno;                     /* The page number for this page */
           75  +  PgHdr *pNextHash, *pPrevHash;  /* Hash collision change for PgHdr.pgno */
           76  +  int nRef;                      /* Number of users of this page */
           77  +  PgHdr *pNext, *pPrev;          /* Freelist of pages where nRef==0 */
           78  +  char inJournal;                /* TRUE if has been written to journal */
           79  +  char dirty;                    /* TRUE if we need to write back changes */
           80  +  /* The page data follows this header */
           81  +};
           82  +
           83  +/*
           84  +** Convert a pointer to a PgHdr into a pointer to its data,
           85  +** and vice verse.
           86  +*/
           87  +#define PGHDR_TO_DATA(P)  ((void*)(&(P)[1]))
           88  +#define DATA_TO_PGHDR(D)  (&((PgHdr*)(D))[-1])
           89  +
           90  +/*
           91  +** The number of page numbers that will fit on one page.
           92  +*/
           93  +#define SQLITE_INDEX_SIZE   (SQLITE_PAGE_SIZE/sizeof(Pgno))
           94  +
           95  +/*
           96  +** How big to make the hash table used for locating in-memory pages
           97  +** by page number.
           98  +*/
           99  +#define N_PG_HASH 353
          100  +
          101  +/*
          102  +** A open page cache is an instance of the following structure.
          103  +*/
          104  +struct Pager {
          105  +  char *zFilename;            /* Name of the database file */
          106  +  char *zJournal;             /* Name of the journal file */
          107  +  int fd, jfd;                /* File descriptors for database and journal */
          108  +  int nRef;                   /* Sum of PgHdr.nRef */
          109  +  int dbSize;                 /* Number of pages in the file */
          110  +  int jSize;                  /* Number of pages in the journal */
          111  +  int nPage;                  /* Total number of in-memory pages */
          112  +  int mxPage;                 /* Maximum number of pages to hold in cache */
          113  +  Pgno *aIdx;                 /* Current journal index page */
          114  +  char state;                 /* SQLITE_UNLOCK, _READLOCK or _WRITELOCK */
          115  +  PgHdr *pFirst, *pLast;      /* List of free pages */
          116  +  PgHdr *aHash[N_PG_HASH];    /* Hash table to map page number of PgHdr */
          117  +};
          118  +
          119  +/*
          120  +** Hash a page number
          121  +*/
          122  +#define sqlite_pager_hash(PN)  ((PN)%N_PG_HASH)
          123  +
          124  +/*
          125  +** Attempt to acquire a read lock (if wrlock==0) or a write lock (if wrlock==1)
          126  +** on the database file.  Return 0 on success and non-zero if the lock 
          127  +** could not be acquired.
          128  +*/
          129  +static int sqlite_pager_lock(int fd, int wrlock){
          130  +  struct flock lock;
          131  +  lock.l_type = write_lock ? F_WRLCK : F_RDLCK;
          132  +  return fcntl(fd, F_SETLK, &lock)!=0;
          133  +}
          134  +
          135  +/*
          136  +** Unlock the database file.
          137  +*/
          138  +static int sqlite_pager_unlock(fd){
          139  +  struct flock lock;
          140  +  lock.l_type = F_UNLCK;
          141  +  return fcntl(fd, F_SETLK, &lock)!=0;
          142  +}
          143  +
          144  +/*
          145  +** Find a page in the hash table given its page number.  Return
          146  +** a pointer to the page or NULL if not found.
          147  +*/
          148  +static PgHdr *sqlite_pager_lookup(Pager *pPager, Pgno pgno){
          149  +  PgHdr *p = pPager->aHash[pgno % N_PG_HASH];
          150  +  while( p && p->pgno!=pgno ){
          151  +    p = p->pNextHash;
          152  +  }
          153  +  return p;
          154  +}
          155  +
          156  +/*
          157  +** Unlock the database and clear the in-memory cache.  This routine
          158  +** sets the state of the pager back to what it was when it was first
          159  +** opened.  Any outstanding pages are invalidated and subsequent attempts
          160  +** to access those pages will likely result in a coredump.
          161  +*/
          162  +static void sqlite_pager_reset(Pager *pPager){
          163  +  PgHdr *pPg, *pNext;
          164  +  for(pPg=pPager->pFirst; pPg; pPg=pNext){
          165  +    pNext = pPg->pNext;
          166  +    sqlite_free(pPg);
          167  +  }
          168  +  pPager->pFirst = 0;
          169  +  pPager->pNext = 0;
          170  +  memset(pPager->aHash, 0, sizeof(pPager->aHash));
          171  +  pPager->nPage = 0;
          172  +  if( pPager->state==SQLITE_WRITELOCK ){
          173  +    sqlite_pager_rollback(pPager);
          174  +  }
          175  +  sqlite_pager_unlock(pPager->fd);
          176  +  pPager->state = SQLITE_UNLOCK;
          177  +  pPager->nRef = 0;
          178  +}
          179  +
          180  +/*
          181  +** When this routine is called, the pager has the journal file open and
          182  +** a write lock on the database.  This routine releases the database
          183  +** write lock and acquires a read lock in its place.  The journal file
          184  +** is deleted and closed.
          185  +**
          186  +** We have to release the write lock before acquiring the read lock,
          187  +** so there is a race condition where another process can get the lock
          188  +** while we are not holding it.  But, no other process should do this
          189  +** because we are also holding a lock on the journal, and no process
          190  +** should get a write lock on the database without first getting a lock
          191  +** on the journal.  So this routine should never fail.  But it can fail
          192  +** if another process is not playing by the rules.  If it does fail,
          193  +** all in-memory cache pages are invalidated and this routine returns
          194  +** SQLITE_PROTOCOL.  SQLITE_OK is returned on success.
          195  +*/
          196  +static int sqlite_pager_unwritelock(Pager *pPager){
          197  +  int rc;
          198  +  assert( pPager->state==SQLITE_WRITELOCK );
          199  +  sqlite_pager_unlock(pPager->fd);
          200  +  rc = sqlite_pager_lock(pPager->fd, 0);
          201  +  unlink(pPager->zJournal);
          202  +  close(pPager->jfd);
          203  +  pPager->jfd = -1;
          204  +  if( rc!=SQLITE_OK ){
          205  +    pPager->state = SQLITE_UNLOCK;
          206  +    sqlite_pager_reset(pPager);
          207  +    rc = SQLITE_PROTOCOL;
          208  +  }else{
          209  +    pPager->state = SQLITE_READLOCK;
          210  +  }
          211  +  return rc;
          212  +}
          213  +
          214  +
          215  +/*
          216  +** Playback the journal and thus restore the database file to
          217  +** the state it was in before we started making changes.  
          218  +**
          219  +** A journal consists of multiple segments.  Every segment begins
          220  +** with a single page containing SQLITE_INDEX_SIZE page numbers.  This
          221  +** first page is called the index.  Most segments have SQLITE_INDEX_SIZE
          222  +** additional pages after the index.  The N-th page after the index
          223  +** contains the contents of a page in the database file before that
          224  +** page was changed.  The N-th entry in the index tells which page
          225  +** of the index file the data is for.
          226  +**
          227  +** The first segment of a journal is formatted slightly differently.
          228  +** The first segment contains an index but only SQLITE_INDEX_SIZE-1
          229  +** data pages.  The first page number in the index is actually the
          230  +** total number of pages in the original file.  This number is used
          231  +** to truncate the original database file back to its original size.
          232  +** The second number in the index page is the page number for the
          233  +** first data page.  And so forth.
          234  +**
          235  +** We really need to playback the journal beginning at the end
          236  +** and working backwards toward the beginning.  That way changes
          237  +** to the database are undone in the reverse order from the way they
          238  +** were applied.  This is important if the same page is changed
          239  +** more than once.  But many operating systems work more efficiently
          240  +** if data is read forward instead of backwards.  So for efficiency
          241  +** we want to read the data in the forward direction.
          242  +**
          243  +** This routine starts with the last segment and works backwards
          244  +** toward the first.  Within each segment, however, data is read
          245  +** in the forward direction for efficiency.  Care is taken that
          246  +** only the first appearance of each page is copied over to the
          247  +** database file.  If a page appears in the index more than once,
          248  +** only the first occurrance is written.  A hash table is used to
          249  +** keep track of  which pages have been written and which have not.
          250  +*/
          251  +static int sqlite_pager_playback(Pager *pPager){
          252  +  int nSeg;                           /* Number of segments */
          253  +  int i, j;                           /* Loop counters */
          254  +  Pgno mxPg = 0;                      /* Size of the original file in pages */
          255  +  struct stat statbuf;                /* Used to size the journal */
          256  +  Pgno aIndex[SQLITE_INDEX_SIZE];     /* The index page */
          257  +  char aBuf[SQLITE_PAGE_SIZE];        /* Page transfer buffer */
          258  +  Pgno aHash[SQLITE_INDEX_SIZE*2-1];  /* Hash table for pages read so far */
          259  +  int rc;
          260  +
          261  +  /* Figure out how many segments are in the journal.  Remember that
          262  +  ** the first segment is one page shorter than the others and that
          263  +  ** the last segment may be incomplete.
          264  +  */
          265  +  if( fstat(pPager->jfd; &statbuf)!=0 ){
          266  +    return SQLITE_OK;
          267  +  }
          268  +  if( statbuf.st_size <= SQLITE_INDEX_SIZE*SQLITE_PAGE_SIZE ){
          269  +    nSeg = 1;
          270  +  }else{
          271  +    int nPage = statbuf.st_size/SQLITE_PAGE_SIZE;
          272  +    nPage -= SQLITE_INDEX_SIZE;
          273  +    nSeg = 1 + nPage/(SQLITE_INDEX_SIZE+1);
          274  +  }
          275  +
          276  +  /* Process segments beginning with the last and working backwards
          277  +  ** to the first.
          278  +  */
          279  +  for(i=nSeg-1; i>=0; i--){
          280  +    /* Seek to the beginning of the segment */
          281  +    sqlite_pager_seekpage(pPager->jfd, 
          282  +        i>0 ? i*(SQLITE_INDEX_SIZE + 1) - 1 : 0,
          283  +        SEEK_SET
          284  +    );
          285  +
          286  +    /* Initialize the hash table used to avoid copying duplicate pages */
          287  +    memset(aHash, 0, sizeof(aHash));
          288  +
          289  +    /* Read the index page */
          290  +    sqlite_pager_readpage(pPager->jfd, aIndex);
          291  +
          292  +    /* Extract the original file size from the first index entry if this
          293  +    ** is the first segment */   
          294  +    if( i==0 ){
          295  +      mxPg = aIndex[0];
          296  +      aIndex[0] = 0;
          297  +    }
          298  +
          299  +    /* Process pages of this segment in forward order
          300  +    */
          301  +    for(j=0; j<SQLITE_INDEX_SIZE; j++){
          302  +      Pgno pgno = aIndex[i];
          303  +      void *pBuf;
          304  +      PgHdr *pPg;
          305  +
          306  +      /* 0 means "no such page".  Skip zero entries */
          307  +      if( pgno==0 ) continue;
          308  +
          309  +      /* Check to see if pgno is in the hash table.  Skip this
          310  +      ** entry if it is.
          311  +      */
          312  +      h = pgno % (SQLITE_PAGE_SIZE-1);
          313  +      while( aHash[h]!=0 && aHash[h]!=pgno ){
          314  +        h++;
          315  +        if( h>=SQLITE_PAGE_SIZE-1 ) h = 0;
          316  +      }
          317  +      if( aHash[h]==pgno ){
          318  +        lseek(pPager->jfd, SQLITE_PAGE_SIZE, SEEK_CUR);
          319  +        continue;
          320  +      }
          321  +      aHash[h] = pgno;
          322  +
          323  +      /* Playback the page.  Update the in-memory copy of the page
          324  +      ** at the same time, if there is one.
          325  +      */
          326  +      pPg = sqlite_pager_lookup(pPager, pgno);
          327  +      if( pPg ){
          328  +        pBuf = PGHDR_TO_DATA(pPg);
          329  +      }else{
          330  +        pBuf = aBuf;
          331  +      }
          332  +      sqlite_pager_readpage(pPager->jfd, pBuf);
          333  +      sqlite_pager_seekpage(pPager->fd, pgno, SEEK_SET);
          334  +      rc = sqlite_pager_writepage(pPager->fd, pBuf);
          335  +      if( rc!=SQLITE_OK ) return rc;
          336  +    }
          337  +  }
          338  +
          339  +  /* Truncate the database back to its original size
          340  +  */
          341  +  if( mxPg>0 ){
          342  +    ftrucate(pPager->fd, mxPg * SQLITE_PAGE_SIZE);
          343  +  }
          344  +  return SQLITE_OK;
          345  +}
          346  +
          347  +/*
          348  +** Create a new page cache and put a pointer to the page cache in *ppPager.
          349  +** The file to be cached need not exist.  The file is not opened until
          350  +** the first call to sqlite_pager_get() and is only held open until the
          351  +** last page is released using sqlite_pager_unref().
          352  +*/
          353  +int sqlite_pager_open(Pager **ppPager, const char *zFilename, int mxPage){
          354  +  Pager *pPager;
          355  +  int nameLen;
          356  +  int fd;
          357  +
          358  +  fd = open(zFilename, O_RDWR, 0644);
          359  +  if( fd<0 ){
          360  +    return SQLITE_CANTOPEN;
          361  +  }
          362  +  nameLen = strlen(zFilename);
          363  +  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*2 + 30 );
          364  +  if( pPager==0 ) return SQLITE_NOMEM;
          365  +  pPager->zFilename = (char*)&pPager[1];
          366  +  pPager->zJournal = &pPager->zFilename[nameLen+1];
          367  +  strcpy(pPager->zFilename, zFilename);
          368  +  strcpy(pPager->zJournal, zFilename);
          369  +  strcpy(&pPager->zJournal[nameLen], "-journal");
          370  +  pPager->fd = fd;
          371  +  pPager->jfd = -1;
          372  +  pPager->nRef = 0;
          373  +  pPager->dbSize = -1;
          374  +  pPager->nPage = 0;
          375  +  pPager->mxPage = mxPage>10 ? mxPage : 10;
          376  +  pPager->state = SQLITE_UNLOCK;
          377  +  pPager->pFirst = 0;
          378  +  pPager->pLast = 0;
          379  +  memset(pPager->aHash, 0, sizeof(pPager->aHash));
          380  +  *ppPager = pPager;
          381  +  return SQLITE_OK;
          382  +}
          383  +
          384  +/*
          385  +** Return the total number of pages in the file opened by pPager.
          386  +*/
          387  +int sqlite_pager_pagecount(Pager *pPager){
          388  +  int n;
          389  +  struct stat statbuf;
          390  +  if( pPager->dbSize>=0 ){
          391  +    return pPager->dbSize;
          392  +  }
          393  +  if( fstat(pPager->fd, &statbuf)!=0 ){
          394  +    n = 0;
          395  +  }else{
          396  +    n = statbuf.st_size/SQLITE_PAGE_SIZE;
          397  +  }
          398  +  if( pPager->state!=SQLITE_NOLOCK ){
          399  +    pPager->dbSize = n;
          400  +  }
          401  +  return n;
          402  +}
          403  +
          404  +/*
          405  +** Shutdown the page cache.  Free all memory and close all files.
          406  +**
          407  +** If a transaction was in progress when this routine is called, that
          408  +** transaction is rolled back.  All outstanding pages are invalidated
          409  +** and their memory is freed.  Any attempt to use a page associated
          410  +** with this page cache after this function returns will likely
          411  +** result in a coredump.
          412  +*/
          413  +int sqlite_pager_close(Pager *pPager){
          414  +  int i;
          415  +  PgHdr *pPg;
          416  +  switch( pPager->state ){
          417  +    case SQLITE_WRITELOCK: {
          418  +      sqlite_pager_rollback(pPager);
          419  +      sqlite_pager_unlock(pPager->fd);
          420  +      break;
          421  +    }
          422  +    case SQLITE_READLOCK: {
          423  +      sqlite_pager_unlock(pPager->fd);
          424  +      break;
          425  +    }
          426  +    default: {
          427  +      /* Do nothing */
          428  +      break;
          429  +    }
          430  +  }
          431  +  for(i=0; i<N_PG_HASH; i++){
          432  +    PgHdr *pNext;
          433  +    for(pPg=pPager->aHash[i]; pPg; pPg=pNext){
          434  +      pNext = pPg->pNextHash;
          435  +      sqliteFree(pPg);
          436  +    }
          437  +  }
          438  +  if( pPager->fd>=0 ) close(pPager->fd);
          439  +  assert( pPager->jfd<0 );
          440  +  sqliteFree(pPager);
          441  +  return SQLITE_OK;
          442  +}
          443  +
          444  +/*
          445  +** Return the page number for the given page data
          446  +*/
          447  +int sqlite_pager_pagenumber(void *pData){
          448  +  PgHdr *p = DATA_TO_PGHDR(pData);
          449  +  return p->pgno;
          450  +}
          451  +
          452  +/*
          453  +** Acquire a page
          454  +*/
          455  +int sqlite_pager_get(Pager *pPager, int pgno, void **ppPage){
          456  +  PgHdr *pPg;
          457  +
          458  +  /* If this is the first page accessed, then get a read lock
          459  +  ** on the database file.
          460  +  */
          461  +  if( pPager->nRef==0 ){
          462  +    if( sqlite_pager_lock(pPager->fd, 0)!=0 ){
          463  +      *ppPage = 0;
          464  +      return SQLITE_BUSY;
          465  +    }
          466  +
          467  +    /* If a journal file exists, try to play it back.
          468  +    */
          469  +    if( access(pPager->zJournal,0)==0 ){
          470  +       int rc;
          471  +
          472  +       /* Open the journal for exclusive access.  Return SQLITE_BUSY if
          473  +       ** we cannot get exclusive access to the journal file
          474  +       */
          475  +       pPager->jfd = open(pPager->zJournal, O_RDONLY, 0);
          476  +       if( pPager->jfd<0 || sqlite_pager_lock(pPager->jfd, 1)!=0 ){
          477  +         if( pPager->jfd>=0 ){ close(pPager->jfd); pPager->jfd = -1; }
          478  +         sqlite_pager_unlock(pPager->fd);
          479  +         *ppPage = 0;
          480  +         return SQLITE_BUSY;
          481  +       }
          482  +
          483  +       /* Get a write lock on the database */
          484  +       sqlite_pager_unlock(pPager->fd);
          485  +       if( sqlite_pager_lock(pPager->fd, 1)!=0 ){
          486  +         *ppPage = 0;
          487  +         return SQLITE_PROTOCOL;
          488  +       }
          489  +
          490  +       /* Playback and delete the journal.  Drop the database write
          491  +       ** lock and reacquire the read lock.
          492  +       */
          493  +       sqlite_pager_playback(pPager);
          494  +       rc = sqlite_pager_unwritelock(pPager);
          495  +       if( rc!=SQLITE_OK ){ return SQLITE_PROTOCOL; }
          496  +    }
          497  +    pPg = 0;
          498  +  }else{
          499  +    /* Search for page in cache */
          500  +    pPg = sqlite_pager_lookup(pPager, pgno);
          501  +  }
          502  +  if( pPg==0 ){
          503  +    int h;
          504  +    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 ){
          505  +      /* Create a new page */
          506  +      pPg = sqlite_malloc( sizeof(*pPg) + SQLITE_PAGE_SIZE );
          507  +      pPg->pPager = pPager;
          508  +    }else{
          509  +      /* Recycle an older page */
          510  +      pPg = pPager->pFirst;
          511  +      if( pPg->dirty ){
          512  +        int rc;
          513  +        sqlite_pager_seekpage(pPager->fd, pPg->pgno, SEEK_SET);
          514  +        rc = sqlite_pager_writepage(pPager->fd, PGHDR_TO_DATA(pPg));
          515  +        if( rc!=SQLITE_OK ){
          516  +          *ppPage = 0;
          517  +          return rc;
          518  +        }
          519  +      } 
          520  +      pPager->pFirst = pPg->pNext;
          521  +      if( pPager->pFirst ){
          522  +        pPager->pFirst->pPrev = 0;
          523  +      }else{
          524  +        pPager->pLast = 0;
          525  +      }
          526  +      if( pPg->pNextHash ){
          527  +        pPg->pNextHash->pPrevHash = pPg->pPrevHash;
          528  +      }
          529  +      if( pPg->pPrevHash ){
          530  +        pPg->pPrevHash->pNextHash = pPg->pNextHash;
          531  +      }else{
          532  +        h = sqlite_pager_hash(pPg->pgno);
          533  +        assert( pPager->aHash[h]==pPg );
          534  +        pPager->aHash[h] = pPg->pNextHash;
          535  +      }
          536  +    }
          537  +    pPg->pgno = pgno;
          538  +    pPg->inJournal = 0;
          539  +    pPg->dirty = 0;
          540  +    pPg->nRef = 1;
          541  +    h = sqlite_pager_hash(pgno);
          542  +    pPg->pNextHash = pPager->aHash[h];
          543  +    pPager->aHash[h] = pPg;
          544  +    if( pPg->pNextHash ){
          545  +      assert( pPg->pNextHash->pPrevHash==0 );
          546  +      pPg->pNextHash->pPrevHash = pPg;
          547  +    }
          548  +    sqlite_pager_seekpage(pPager->fd, pgno, SEEK_SET);
          549  +    sqlite_pager_readpage(pPager->fd, PGHDR_TO_DATA(pPg));
          550  +  }else{
          551  +    if( pPg->nRef==0 ){
          552  +      if( pPg->pPrev ){
          553  +        pPg->pPrev->pNext = pPg->pNext;
          554  +      }else{
          555  +        pPager->pFirst = pPg->pNext;
          556  +      }
          557  +      if( pPg->pNext ){
          558  +        pPg->pNext->pPrev = pPg->pPrev;
          559  +      }else{
          560  +        pPager->pLast = pPg->pPrev;
          561  +      }
          562  +    }
          563  +    pPg->nRef++;
          564  +  }
          565  +  *ppPage = PGHDR_TO_DATA(pPg);
          566  +  return SQLITE_OK;
          567  +}
          568  +
          569  +/*
          570  +** Release a page.
          571  +**
          572  +** If the number of references to the page drop to zero, then the
          573  +** page is added to the LRU list.  When all references to all pages
          574  +** are released, a rollback occurs, and the lock on the database is
          575  +** removed.
          576  +*/
          577  +int sqlite_pager_unref(void *pData){
          578  +  Pager *pPager;
          579  +  PgHdr *pPg;
          580  +  pPg = DATA_TO_PGHDR(pData);
          581  +  assert( pPg->nRef>0 );
          582  +  pPager = pPg->pPager;
          583  +  pPg->nRef--;
          584  +  if( pPg->nRef==0 ){
          585  +    pPg->pNext = 0;
          586  +    pPg->pPrev = pPager->pLast;
          587  +    pPager->pLast = pPg;
          588  +    if( pPg->pPrev ){
          589  +      pPg->pPrev->pNext = pPg;
          590  +    }else{
          591  +      pPager->pFirst = pPg;
          592  +    }
          593  +  }
          594  +  pPager->nRef--;
          595  +  assert( pPager->nRef>=0 );
          596  +  if( pPager->nRef==0 ){
          597  +    sqlite_pager_reset(pPager);
          598  +  }
          599  +}
          600  +
          601  +/*
          602  +** Mark a data page as writeable.  The page is written into the journal 
          603  +** if it is not there already.  This routine must be called before making
          604  +** changes to a page.
          605  +**
          606  +** The first time this routine is called, the pager creates a new
          607  +** journal and acquires a write lock on the database.  If the write
          608  +** lock could not be acquired, this routine returns SQLITE_BUSY.  The
          609  +** calling routine must check for that routine and be careful not to
          610  +** change any page data until this routine returns SQLITE_OK.
          611  +*/
          612  +int sqlite_pager_write(void *pData){
          613  +  if( pPager->state==SQLITE_READLOCK ){
          614  +    pPager->jfd = open(pPager->zJournal, O_RDWR|O_CREAT, 0644);
          615  +    if( pPager->jfd<0 ){
          616  +      return SQLITE_CANTOPEN;
          617  +    }
          618  +    if( sqlite_pager_lock(pPager->jfd, 1) ){
          619  +      close(pPager->jfd);
          620  +      pPager->jfd = -1;
          621  +      return SQLITE_BUSY;
          622  +    }
          623  +    sqlite_pager_unlock(pPager->fd);
          624  +    if( sqlite_pager_lock(pPager->fd, 1) ){
          625  +      close(pPager->jfd);
          626  +      pPager->jfd = -1;
          627  +      pPager->state = SQLITE_UNLOCK;
          628  +      sqlite_pager_reset(pPager);
          629  +      return SQLITE_PROTOCOL;
          630  +    }
          631  +    pPager->state = SQLITE_WRITELOCK;
          632  +    pPager->jSize = 0;
          633  +  }
          634  +  /* Write this page to the journal */
          635  +}
          636  +
          637  +/*
          638  +** Commit all changes to the database and release the write lock.
          639  +*/
          640  +int sqlite_pager_commit(Pager*){
          641  +  int i, rc;
          642  +  PgHdr *pPg;
          643  +  assert( pPager->state==SQLITE_WRITELOCK );
          644  +  assert( pPager->jfd>=0 );
          645  +  if( fsync(pPager->jfd) ){
          646  +    return SQLITE_IOERR;
          647  +  }
          648  +  for(i=0; i<N_PG_HASH; i++){
          649  +    for(pPg=pPager->aHash[i]; pPg; pPg=pPg->pNextHash){
          650  +      if( pPg->dirty==0 ) continue;
          651  +      rc = sqlite_pager_seekpage(pPager->fd, pPg->pgno, SEEK_SET);
          652  +      if( rc!=SQLITE_OK ) return rc;
          653  +      rc = sqlite_pager_writePage(pPager->fd, PGHDR_TO_DATA(pPg));
          654  +      if( rc!=SQLITE_OK ) return rc;
          655  +    }
          656  +  }
          657  +  if( fsync(pPager->fd) ){
          658  +    return SQLITE_IOERR;
          659  +  }
          660  +  rc = sqlite_pager_unwritelock(pPager);
          661  +  return rc;
          662  +}
          663  +
          664  +/*
          665  +** Rollback all changes.  The database falls back to read-only mode.
          666  +** All in-memory cache pages revert to their original data contents.
          667  +** The journal is deleted.
          668  +*/
          669  +int sqlite_pager_rollback(Pager *pPager){
          670  +  int rc;
          671  +  if( pPager->state!=SQLITE_WRITELOCK ) return SQLITE_OK;
          672  +  rc = sqlite_pager_playback(pPager);
          673  +  if( rc!=SQLITE_OK ){
          674  +    rc = sqlite_pager_unwritelock(pPager);
          675  +  }
          676  +  return rc;
          677  +};

Added test/malloc.test.

            1  +# Copyright (c) 2001 D. Richard Hipp
            2  +#
            3  +# This program is free software; you can redistribute it and/or
            4  +# modify it under the terms of the GNU General Public
            5  +# License as published by the Free Software Foundation; either
            6  +# version 2 of the License, or (at your option) any later version.
            7  +#
            8  +# This program is distributed in the hope that it will be useful,
            9  +# but WITHOUT ANY WARRANTY; without even the implied warranty of
           10  +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
           11  +# General Public License for more details.
           12  +# 
           13  +# You should have received a copy of the GNU General Public
           14  +# License along with this library; if not, write to the
           15  +# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
           16  +# Boston, MA  02111-1307, USA.
           17  +#
           18  +# Author contact information:
           19  +#   drh@hwaci.com
           20  +#   http://www.hwaci.com/drh/
           21  +#
           22  +#***********************************************************************
           23  +# This file attempts to check the library in an out-of-memory situation.
           24  +# When compiled with -DMEMORY_DEBUG=1, the SQLite library accepts a special
           25  +# command (--malloc-fail=N) which causes the N-th malloc to fail.  This
           26  +# special feature is used to see what happens in the library if a malloc
           27  +# were to really fail due to an out-of-memory situation.
           28  +#
           29  +# $Id: malloc.test,v 1.1 2001/04/11 14:29:22 drh Exp $
           30  +
           31  +set testdir [file dirname $argv0]
           32  +source $testdir/tester.tcl
           33  +
           34  +# Only run these tests if memory debugging is turned on.
           35  +#
           36  +if {[info command sqlite_malloc_fail]==""} {
           37  +   puts "Skipping malloc tests: not compiled with -DMEMORY_DEBUG..."
           38  +   finish_test
           39  +   return
           40  +}
           41  +
           42  +for {set go 1; set i 1} {$go} {incr i} {
           43  +  do_test malloc-1.$i {
           44  +     sqlite_malloc_fail 0
           45  +     catch {execsql {DROP TABLE t1}}
           46  +     sqlite_malloc_fail $i
           47  +     set v [catch {execsql {
           48  +        CREATE TABLE t1(
           49  +           a int, b float, c double, d text, e varchar(20),
           50  +           primary key(a,b,c)
           51  +        );
           52  +        CREATE INDEX i1 ON t1(a,b);
           53  +        INSERT INTO t1 VALUES(1,2.3,4.5,'hi','there');
           54  +        INSERT INTO t1 VALUES(6,7.0,0.8,'hello','out yonder');
           55  +        SELECT * FROM t1;
           56  +        SELECT avg(b) FROM t1 GROUP BY a;
           57  +        DELETE FROM t1 WHERE a==6;
           58  +        SELECT count(*) FROM t1;
           59  +     }} msg]
           60  +     if {[lindex [sqlite_malloc_stat] 2]>0} {
           61  +       set ::go 0
           62  +       set v {1 1}
           63  +     } else {
           64  +       lappend v [expr {$msg=="" || $msg=="out of memory"}]
           65  +     }
           66  +  } {1 1}
           67  +}
           68  +sqlite_malloc_fail 0
           69  +finish_test