Back to index

php5  5.3.10
Classes | Defines | Typedefs | Functions | Variables
pager.c File Reference
#include "os.h"
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

Go to the source code of this file.

Classes

struct  PgHdr
struct  Pager
struct  PageRecord

Defines

#define SET_PAGER(X)
#define CLR_PAGER(X)
#define TRACE1(X)
#define TRACE2(X, Y)
#define TRACE3(X, Y, Z)
#define SQLITE_UNLOCK   0
#define SQLITE_READLOCK   1
#define SQLITE_WRITELOCK   2
#define CODEC(P, D, N, X)
#define PGHDR_TO_DATA(P)   ((void*)(&(P)[1]))
#define DATA_TO_PGHDR(D)   (&((PgHdr*)(D))[-1])
#define PGHDR_TO_EXTRA(P)   ((void*)&((char*)(&(P)[1]))[SQLITE_PAGE_SIZE])
#define N_PG_HASH   2048
#define pager_hash(PN)   ((PN)&(N_PG_HASH-1))
#define PAGER_ERR_FULL   0x01 /* a write() failed */
#define PAGER_ERR_MEM   0x02 /* malloc() failed */
#define PAGER_ERR_LOCK   0x04 /* error in the locking protocol */
#define PAGER_ERR_CORRUPT   0x08 /* database or journal corruption */
#define PAGER_ERR_DISK   0x10 /* general disk I/O error - bad hard drive? */
#define JOURNAL_FORMAT_1   1
#define JOURNAL_FORMAT_2   2
#define JOURNAL_FORMAT_3   3
#define journal_format   3
#define JOURNAL_HDR_SZ(X)   (sizeof(aJournalMagic1) + sizeof(Pgno) + ((X)>=3)*2*sizeof(u32))
#define JOURNAL_PG_SZ(X)   (SQLITE_PAGE_SIZE + sizeof(Pgno) + ((X)>=3)*sizeof(u32))
#define REFINFO(X)
#define page_ref(P)   ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)

Typedefs

typedef struct PgHdr
typedef struct PageRecord

Functions

static int read32bits (int format, OsFile *fd, u32 *pRes)
static int write32bits (OsFile *fd, u32 val)
static void store32bits (u32 val, PgHdr *p, int offset)
static int pager_errcode (Pager *pPager)
static void page_add_to_ckpt_list (PgHdr *pPg)
static void page_remove_from_ckpt_list (PgHdr *pPg)
static PgHdrpager_lookup (Pager *pPager, Pgno pgno)
static void pager_reset (Pager *pPager)
static int pager_unwritelock (Pager *pPager)
static u32 pager_cksum (Pager *pPager, Pgno pgno, const char *aData)
static int pager_playback_one_page (Pager *pPager, OsFile *jfd, int format)
static int pager_playback (Pager *pPager, int useJournalSize)
static int pager_ckpt_playback (Pager *pPager)
void sqlitepager_set_cachesize (Pager *pPager, int mxPage)
void sqlitepager_set_safety_level (Pager *pPager, int level)
static int sqlitepager_opentemp (char *zFile, OsFile *fd)
int sqlitepager_open (Pager **ppPager, const char *zFilename, int mxPage, int nExtra, int useJournal)
void sqlitepager_set_destructor (Pager *pPager, void(*xDesc)(void *))
int sqlitepager_pagecount (Pager *pPager)
static int syncJournal (Pager *)
int sqlitepager_truncate (Pager *pPager, Pgno nPage)
int sqlitepager_close (Pager *pPager)
Pgno sqlitepager_pagenumber (void *pData)
static void _page_ref (PgHdr *pPg)
int sqlitepager_ref (void *pData)
static int pager_write_pagelist (PgHdr *pList)
static PgHdrpager_get_all_dirty_pages (Pager *pPager)
int sqlitepager_get (Pager *pPager, Pgno pgno, void **ppPage)
void * sqlitepager_lookup (Pager *pPager, Pgno pgno)
int sqlitepager_unref (void *pData)
static int pager_open_journal (Pager *pPager)
int sqlitepager_begin (void *pData)
int sqlitepager_write (void *pData)
int sqlitepager_iswriteable (void *pData)
int sqlitepager_overwrite (Pager *pPager, Pgno pgno, void *pData)
void sqlitepager_dont_write (Pager *pPager, Pgno pgno)
void sqlitepager_dont_rollback (void *pData)
int sqlitepager_commit (Pager *pPager)
int sqlitepager_rollback (Pager *pPager)
int sqlitepager_isreadonly (Pager *pPager)
intsqlitepager_stats (Pager *pPager)
int sqlitepager_ckpt_begin (Pager *pPager)
int sqlitepager_ckpt_commit (Pager *pPager)
int sqlitepager_ckpt_rollback (Pager *pPager)
const char * sqlitepager_filename (Pager *pPager)
void sqlitepager_set_codec (Pager *pPager, void(*xCodec)(void *, void *, Pgno, int), void *pCodecArg)

Variables

static const unsigned char aJournalMagic1 []
static const unsigned char aJournalMagic2 []
static const unsigned char aJournalMagic3 []

Class Documentation

struct PgHdr

Definition at line 102 of file pager.c.

Collaboration diagram for PgHdr:
Class Members
u8 alwaysRollback
u8 dirty
u16 flags
u8 inCkpt
u8 inJournal
u8 needSync
int nRef
i16 nRef
PCache * pCache
void * pData
PgHdr * pDirty
PgHdr * pDirtyNext
PgHdr * pDirtyPrev
void * pExtra
Pgno pgno
PgHdr * pNextAll
PgHdr * pNextCkpt
PgHdr * pNextFree
PgHdr * pNextHash
Pager * pPager
PgHdr * pPrevAll
PgHdr * pPrevCkpt
PgHdr * pPrevFree
PgHdr * pPrevHash
struct PageRecord

Definition at line 215 of file pager.c.

Class Members
char aData
Pgno pgno

Define Documentation

#define CLR_PAGER (   X)

Definition at line 41 of file pager.c.

#define CODEC (   P,
  D,
  N,
  X 
)

Definition at line 127 of file pager.c.

#define DATA_TO_PGHDR (   D)    (&((PgHdr*)(D))[-1])

Definition at line 135 of file pager.c.

#define journal_format   3

Definition at line 274 of file pager.c.

#define JOURNAL_FORMAT_1   1

Definition at line 258 of file pager.c.

#define JOURNAL_FORMAT_2   2

Definition at line 259 of file pager.c.

#define JOURNAL_FORMAT_3   3

Definition at line 260 of file pager.c.

#define JOURNAL_HDR_SZ (   X)    (sizeof(aJournalMagic1) + sizeof(Pgno) + ((X)>=3)*2*sizeof(u32))

Definition at line 282 of file pager.c.

#define JOURNAL_PG_SZ (   X)    (SQLITE_PAGE_SIZE + sizeof(Pgno) + ((X)>=3)*sizeof(u32))

Definition at line 284 of file pager.c.

#define N_PG_HASH   2048

Definition at line 142 of file pager.c.

#define page_ref (   P)    ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)

Definition at line 1120 of file pager.c.

#define PAGER_ERR_CORRUPT   0x08 /* database or journal corruption */

Definition at line 203 of file pager.c.

#define PAGER_ERR_DISK   0x10 /* general disk I/O error - bad hard drive? */

Definition at line 204 of file pager.c.

#define PAGER_ERR_FULL   0x01 /* a write() failed */

Definition at line 200 of file pager.c.

#define PAGER_ERR_LOCK   0x04 /* error in the locking protocol */

Definition at line 202 of file pager.c.

#define PAGER_ERR_MEM   0x02 /* malloc() failed */

Definition at line 201 of file pager.c.

#define pager_hash (   PN)    ((PN)&(N_PG_HASH-1))

Definition at line 147 of file pager.c.

#define PGHDR_TO_DATA (   P)    ((void*)(&(P)[1]))

Definition at line 134 of file pager.c.

#define PGHDR_TO_EXTRA (   P)    ((void*)&((char*)(&(P)[1]))[SQLITE_PAGE_SIZE])

Definition at line 136 of file pager.c.

#define REFINFO (   X)

Definition at line 303 of file pager.c.

#define SET_PAGER (   X)

Definition at line 40 of file pager.c.

#define SQLITE_READLOCK   1

Definition at line 79 of file pager.c.

#define SQLITE_UNLOCK   0

Definition at line 78 of file pager.c.

#define SQLITE_WRITELOCK   2

Definition at line 80 of file pager.c.

#define TRACE1 (   X)

Definition at line 42 of file pager.c.

#define TRACE2 (   X,
 
)

Definition at line 43 of file pager.c.

#define TRACE3 (   X,
  Y,
  Z 
)

Definition at line 44 of file pager.c.


Typedef Documentation

typedef struct PageRecord

Definition at line 214 of file pager.c.

typedef struct PgHdr

Definition at line 101 of file pager.c.


Function Documentation

static void _page_ref ( PgHdr pPg) [static]

Definition at line 1121 of file pager.c.

                                 {
  if( pPg->nRef==0 ){
    /* The page is currently on the freelist.  Remove it. */
    if( pPg==pPg->pPager->pFirstSynced ){
      PgHdr *p = pPg->pNextFree;
      while( p && p->needSync ){ p = p->pNextFree; }
      pPg->pPager->pFirstSynced = p;
    }
    if( pPg->pPrevFree ){
      pPg->pPrevFree->pNextFree = pPg->pNextFree;
    }else{
      pPg->pPager->pFirst = pPg->pNextFree;
    }
    if( pPg->pNextFree ){
      pPg->pNextFree->pPrevFree = pPg->pPrevFree;
    }else{
      pPg->pPager->pLast = pPg->pPrevFree;
    }
    pPg->pPager->nRef++;
  }
  pPg->nRef++;
  REFINFO(pPg);
}
static void page_add_to_ckpt_list ( PgHdr pPg) [static]

Definition at line 393 of file pager.c.

                                             {
  Pager *pPager = pPg->pPager;
  if( pPg->inCkpt ) return;
  assert( pPg->pPrevCkpt==0 && pPg->pNextCkpt==0 );
  pPg->pPrevCkpt = 0;
  if( pPager->pCkpt ){
    pPager->pCkpt->pPrevCkpt = pPg;
  }
  pPg->pNextCkpt = pPager->pCkpt;
  pPager->pCkpt = pPg;
  pPg->inCkpt = 1;
}

Here is the caller graph for this function:

static void page_remove_from_ckpt_list ( PgHdr pPg) [static]

Definition at line 405 of file pager.c.

                                                  {
  if( !pPg->inCkpt ) return;
  if( pPg->pPrevCkpt ){
    assert( pPg->pPrevCkpt->pNextCkpt==pPg );
    pPg->pPrevCkpt->pNextCkpt = pPg->pNextCkpt;
  }else{
    assert( pPg->pPager->pCkpt==pPg );
    pPg->pPager->pCkpt = pPg->pNextCkpt;
  }
  if( pPg->pNextCkpt ){
    assert( pPg->pNextCkpt->pPrevCkpt==pPg );
    pPg->pNextCkpt->pPrevCkpt = pPg->pPrevCkpt;
  }
  pPg->pNextCkpt = 0;
  pPg->pPrevCkpt = 0;
  pPg->inCkpt = 0;
}

Here is the caller graph for this function:

static int pager_ckpt_playback ( Pager pPager) [static]

Definition at line 775 of file pager.c.

                                             {
  off_t szJ;               /* Size of the full journal */
  int nRec;                /* Number of Records */
  int i;                   /* Loop counter */
  int rc;

  /* Truncate the database back to its original size.
  */
  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)pPager->ckptSize);
  pPager->dbSize = pPager->ckptSize;

  /* Figure out how many records are in the checkpoint journal.
  */
  assert( pPager->ckptInUse && pPager->journalOpen );
  sqliteOsSeek(&pPager->cpfd, 0);
  nRec = pPager->ckptNRec;
  
  /* Copy original pages out of the checkpoint journal and back into the
  ** database file.  Note that the checkpoint journal always uses format
  ** 2 instead of format 3 since it does not need to be concerned with
  ** power failures corrupting the journal and can thus omit the checksums.
  */
  for(i=nRec-1; i>=0; i--){
    rc = pager_playback_one_page(pPager, &pPager->cpfd, 2);
    assert( rc!=SQLITE_DONE );
    if( rc!=SQLITE_OK ) goto end_ckpt_playback;
  }

  /* Figure out how many pages need to be copied out of the transaction
  ** journal.
  */
  rc = sqliteOsSeek(&pPager->jfd, pPager->ckptJSize);
  if( rc!=SQLITE_OK ){
    goto end_ckpt_playback;
  }
  rc = sqliteOsFileSize(&pPager->jfd, &szJ);
  if( rc!=SQLITE_OK ){
    goto end_ckpt_playback;
  }
  nRec = (szJ - pPager->ckptJSize)/JOURNAL_PG_SZ(journal_format);
  for(i=nRec-1; i>=0; i--){
    rc = pager_playback_one_page(pPager, &pPager->jfd, journal_format);
    if( rc!=SQLITE_OK ){
      assert( rc!=SQLITE_DONE );
      goto end_ckpt_playback;
    }
  }
  
end_ckpt_playback:
  if( rc!=SQLITE_OK ){
    pPager->errMask |= PAGER_ERR_CORRUPT;
    rc = SQLITE_CORRUPT;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static u32 pager_cksum ( Pager pPager,
Pgno  pgno,
const char *  aData 
) [static]

Definition at line 516 of file pager.c.

                                                                   {
  u32 cksum = pPager->cksumInit + pgno;
  return cksum;
}

Here is the caller graph for this function:

static int pager_errcode ( Pager pPager) [static]

Definition at line 374 of file pager.c.

                                       {
  int rc = SQLITE_OK;
  if( pPager->errMask & PAGER_ERR_LOCK )    rc = SQLITE_PROTOCOL;
  if( pPager->errMask & PAGER_ERR_DISK )    rc = SQLITE_IOERR;
  if( pPager->errMask & PAGER_ERR_FULL )    rc = SQLITE_FULL;
  if( pPager->errMask & PAGER_ERR_MEM )     rc = SQLITE_NOMEM;
  if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT;
  return rc;
}

Here is the caller graph for this function:

static PgHdr* pager_get_all_dirty_pages ( Pager pPager) [static]

Definition at line 1276 of file pager.c.

                                                      {
  PgHdr *p, *pList;
  pList = 0;
  for(p=pPager->pAll; p; p=p->pNextAll){
    if( p->dirty ){
      p->pDirty = pList;
      pList = p;
    }
  }
  return pList;
}

Here is the caller graph for this function:

static PgHdr* pager_lookup ( Pager pPager,
Pgno  pgno 
) [static]

Definition at line 427 of file pager.c.

                                                    {
  PgHdr *p = pPager->aHash[pager_hash(pgno)];
  while( p && p->pgno!=pgno ){
    p = p->pNextHash;
  }
  return p;
}

Here is the caller graph for this function:

static int pager_open_journal ( Pager pPager) [static]

Definition at line 1633 of file pager.c.

                                            {
  int rc;
  assert( pPager->state==SQLITE_WRITELOCK );
  assert( pPager->journalOpen==0 );
  assert( pPager->useJournal );
  sqlitepager_pagecount(pPager);
  pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
  if( pPager->aInJournal==0 ){
    sqliteOsReadLock(&pPager->fd);
    pPager->state = SQLITE_READLOCK;
    return SQLITE_NOMEM;
  }
  rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
  if( rc!=SQLITE_OK ){
    sqliteFree(pPager->aInJournal);
    pPager->aInJournal = 0;
    sqliteOsReadLock(&pPager->fd);
    pPager->state = SQLITE_READLOCK;
    return SQLITE_CANTOPEN;
  }
  sqliteOsOpenDirectory(pPager->zDirectory, &pPager->jfd);
  pPager->journalOpen = 1;
  pPager->journalStarted = 0;
  pPager->needSync = 0;
  pPager->alwaysRollback = 0;
  pPager->nRec = 0;
  if( pPager->errMask!=0 ){
    rc = pager_errcode(pPager);
    return rc;
  }
  pPager->origDbSize = pPager->dbSize;
  if( journal_format==JOURNAL_FORMAT_3 ){
    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic3, sizeof(aJournalMagic3));
    if( rc==SQLITE_OK ){
      rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
    }
    if( rc==SQLITE_OK ){
      sqliteRandomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
      rc = write32bits(&pPager->jfd, pPager->cksumInit);
    }
  }else if( journal_format==JOURNAL_FORMAT_2 ){
    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic2, sizeof(aJournalMagic2));
  }else{
    assert( journal_format==JOURNAL_FORMAT_1 );
    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic1, sizeof(aJournalMagic1));
  }
  if( rc==SQLITE_OK ){
    rc = write32bits(&pPager->jfd, pPager->dbSize);
  }
  if( pPager->ckptAutoopen && rc==SQLITE_OK ){
    rc = sqlitepager_ckpt_begin(pPager);
  }
  if( rc!=SQLITE_OK ){
    rc = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
  return rc;  
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pager_playback ( Pager pPager,
int  useJournalSize 
) [static]

Definition at line 632 of file pager.c.

                                                            {
  off_t szJ;               /* Size of the journal file in bytes */
  int nRec;                /* Number of Records in the journal */
  int i;                   /* Loop counter */
  Pgno mxPg = 0;           /* Size of the original file in pages */
  int format;              /* Format of the journal file. */
  unsigned char aMagic[sizeof(aJournalMagic1)];
  int rc;

  /* Figure out how many records are in the journal.  Abort early if
  ** the journal is empty.
  */
  assert( pPager->journalOpen );
  sqliteOsSeek(&pPager->jfd, 0);
  rc = sqliteOsFileSize(&pPager->jfd, &szJ);
  if( rc!=SQLITE_OK ){
    goto end_playback;
  }

  /* If the journal file is too small to contain a complete header,
  ** it must mean that the process that created the journal was just
  ** beginning to write the journal file when it died.  In that case,
  ** the database file should have still been completely unchanged.
  ** Nothing needs to be rolled back.  We can safely ignore this journal.
  */
  if( szJ < sizeof(aMagic)+sizeof(Pgno) ){
    goto end_playback;
  }

  /* Read the beginning of the journal and truncate the
  ** database file back to its original size.
  */
  rc = sqliteOsRead(&pPager->jfd, aMagic, sizeof(aMagic));
  if( rc!=SQLITE_OK ){
    rc = SQLITE_PROTOCOL;
    goto end_playback;
  }
  if( memcmp(aMagic, aJournalMagic3, sizeof(aMagic))==0 ){
    format = JOURNAL_FORMAT_3;
  }else if( memcmp(aMagic, aJournalMagic2, sizeof(aMagic))==0 ){
    format = JOURNAL_FORMAT_2;
  }else if( memcmp(aMagic, aJournalMagic1, sizeof(aMagic))==0 ){
    format = JOURNAL_FORMAT_1;
  }else{
    rc = SQLITE_PROTOCOL;
    goto end_playback;
  }
  if( format>=JOURNAL_FORMAT_3 ){
    if( szJ < sizeof(aMagic) + 3*sizeof(u32) ){
      /* Ignore the journal if it is too small to contain a complete
      ** header.  We already did this test once above, but at the prior
      ** test, we did not know the journal format and so we had to assume
      ** the smallest possible header.  Now we know the header is bigger
      ** than the minimum so we test again.
      */
      goto end_playback;
    }
    rc = read32bits(format, &pPager->jfd, (u32*)&nRec);
    if( rc ) goto end_playback;
    rc = read32bits(format, &pPager->jfd, &pPager->cksumInit);
    if( rc ) goto end_playback;
    if( nRec==0xffffffff || useJournalSize ){
      nRec = (szJ - JOURNAL_HDR_SZ(3))/JOURNAL_PG_SZ(3);
    }
  }else{
    nRec = (szJ - JOURNAL_HDR_SZ(2))/JOURNAL_PG_SZ(2);
    assert( nRec*JOURNAL_PG_SZ(2)+JOURNAL_HDR_SZ(2)==szJ );
  }
  rc = read32bits(format, &pPager->jfd, &mxPg);
  if( rc!=SQLITE_OK ){
    goto end_playback;
  }
  assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)mxPg);
  if( rc!=SQLITE_OK ){
    goto end_playback;
  }
  pPager->dbSize = mxPg;
  
  /* Copy original pages out of the journal and back into the database file.
  */
  for(i=0; i<nRec; i++){
    rc = pager_playback_one_page(pPager, &pPager->jfd, format);
    if( rc!=SQLITE_OK ){
      if( rc==SQLITE_DONE ){
        rc = SQLITE_OK;
      }
      break;
    }
  }

  /* Pages that have been written to the journal but never synced
  ** where not restored by the loop above.  We have to restore those
  ** pages by reading them back from the original database.
  */
  if( rc==SQLITE_OK ){
    PgHdr *pPg;
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      char zBuf[SQLITE_PAGE_SIZE];
      if( !pPg->dirty ) continue;
      if( (int)pPg->pgno <= pPager->origDbSize ){
        sqliteOsSeek(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)(pPg->pgno-1));
        rc = sqliteOsRead(&pPager->fd, zBuf, SQLITE_PAGE_SIZE);
        TRACE2("REFETCH %d\n", pPg->pgno);
        CODEC(pPager, zBuf, pPg->pgno, 2);
        if( rc ) break;
      }else{
        memset(zBuf, 0, SQLITE_PAGE_SIZE);
      }
      if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE) ){
        memcpy(PGHDR_TO_DATA(pPg), zBuf, SQLITE_PAGE_SIZE);
        memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
      }
      pPg->needSync = 0;
      pPg->dirty = 0;
    }
  }

end_playback:
  if( rc!=SQLITE_OK ){
    pager_unwritelock(pPager);
    pPager->errMask |= PAGER_ERR_CORRUPT;
    rc = SQLITE_CORRUPT;
  }else{
    rc = pager_unwritelock(pPager);
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pager_playback_one_page ( Pager pPager,
OsFile jfd,
int  format 
) [static]

Definition at line 528 of file pager.c.

                                                                          {
  int rc;
  PgHdr *pPg;              /* An existing page in the cache */
  PageRecord pgRec;
  u32 cksum;

  rc = read32bits(format, jfd, &pgRec.pgno);
  if( rc!=SQLITE_OK ) return rc;
  rc = sqliteOsRead(jfd, &pgRec.aData, sizeof(pgRec.aData));
  if( rc!=SQLITE_OK ) return rc;

  /* Sanity checking on the page.  This is more important that I originally
  ** thought.  If a power failure occurs while the journal is being written,
  ** it could cause invalid data to be written into the journal.  We need to
  ** detect this invalid data (with high probability) and ignore it.
  */
  if( pgRec.pgno==0 ){
    return SQLITE_DONE;
  }
  if( pgRec.pgno>(unsigned)pPager->dbSize ){
    return SQLITE_OK;
  }
  if( format>=JOURNAL_FORMAT_3 ){
    rc = read32bits(format, jfd, &cksum);
    if( rc ) return rc;
    if( pager_cksum(pPager, pgRec.pgno, pgRec.aData)!=cksum ){
      return SQLITE_DONE;
    }
  }

  /* Playback the page.  Update the in-memory copy of the page
  ** at the same time, if there is one.
  */
  pPg = pager_lookup(pPager, pgRec.pgno);
  TRACE2("PLAYBACK %d\n", pgRec.pgno);
  sqliteOsSeek(&pPager->fd, (pgRec.pgno-1)*(off_t)SQLITE_PAGE_SIZE);
  rc = sqliteOsWrite(&pPager->fd, pgRec.aData, SQLITE_PAGE_SIZE);
  if( pPg ){
    /* No page should ever be rolled back that is in use, except for page
    ** 1 which is held in use in order to keep the lock on the database
    ** active.
    */
    assert( pPg->nRef==0 || pPg->pgno==1 );
    memcpy(PGHDR_TO_DATA(pPg), pgRec.aData, SQLITE_PAGE_SIZE);
    memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
    pPg->dirty = 0;
    pPg->needSync = 0;
    CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void pager_reset ( Pager pPager) [static]

Definition at line 441 of file pager.c.

                                      {
  PgHdr *pPg, *pNext;
  for(pPg=pPager->pAll; pPg; pPg=pNext){
    pNext = pPg->pNextAll;
    sqliteFree(pPg);
  }
  pPager->pFirst = 0;
  pPager->pFirstSynced = 0;
  pPager->pLast = 0;
  pPager->pAll = 0;
  memset(pPager->aHash, 0, sizeof(pPager->aHash));
  pPager->nPage = 0;
  if( pPager->state>=SQLITE_WRITELOCK ){
    sqlitepager_rollback(pPager);
  }
  sqliteOsUnlock(&pPager->fd);
  pPager->state = SQLITE_UNLOCK;
  pPager->dbSize = -1;
  pPager->nRef = 0;
  assert( pPager->journalOpen==0 );
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pager_unwritelock ( Pager pPager) [static]

Definition at line 473 of file pager.c.

                                           {
  int rc;
  PgHdr *pPg;
  if( pPager->state<SQLITE_WRITELOCK ) return SQLITE_OK;
  sqlitepager_ckpt_commit(pPager);
  if( pPager->ckptOpen ){
    sqliteOsClose(&pPager->cpfd);
    pPager->ckptOpen = 0;
  }
  if( pPager->journalOpen ){
    sqliteOsClose(&pPager->jfd);
    pPager->journalOpen = 0;
    sqliteOsDelete(pPager->zJournal);
    sqliteFree( pPager->aInJournal );
    pPager->aInJournal = 0;
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      pPg->inJournal = 0;
      pPg->dirty = 0;
      pPg->needSync = 0;
    }
  }else{
    assert( pPager->dirtyFile==0 || pPager->useJournal==0 );
  }
  rc = sqliteOsReadLock(&pPager->fd);
  if( rc==SQLITE_OK ){
    pPager->state = SQLITE_READLOCK;
  }else{
    /* This can only happen if a process does a BEGIN, then forks and the
    ** child process does the COMMIT.  Because of the semantics of unix
    ** file locking, the unlock will fail.
    */
    pPager->state = SQLITE_UNLOCK;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int pager_write_pagelist ( PgHdr pList) [static]

Definition at line 1251 of file pager.c.

                                             {
  Pager *pPager;
  int rc;

  if( pList==0 ) return SQLITE_OK;
  pPager = pList->pPager;
  while( pList ){
    assert( pList->dirty );
    sqliteOsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
    TRACE2("STORE %d\n", pList->pgno);
    rc = sqliteOsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE);
    CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
    if( rc ) return rc;
    pList->dirty = 0;
    pList = pList->pDirty;
  }
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int read32bits ( int  format,
OsFile fd,
u32 pRes 
) [static]

Definition at line 315 of file pager.c.

                                                        {
  u32 res;
  int rc;
  rc = sqliteOsRead(fd, &res, sizeof(res));
  if( rc==SQLITE_OK && format>JOURNAL_FORMAT_1 ){
    unsigned char ac[4];
    memcpy(ac, &res, 4);
    res = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3];
  }
  *pRes = res;
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_begin ( void *  pData)

Definition at line 1714 of file pager.c.

                                  {
  PgHdr *pPg = DATA_TO_PGHDR(pData);
  Pager *pPager = pPg->pPager;
  int rc = SQLITE_OK;
  assert( pPg->nRef>0 );
  assert( pPager->state!=SQLITE_UNLOCK );
  if( pPager->state==SQLITE_READLOCK ){
    assert( pPager->aInJournal==0 );
    rc = sqliteOsWriteLock(&pPager->fd);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pPager->state = SQLITE_WRITELOCK;
    pPager->dirtyFile = 0;
    TRACE1("TRANSACTION\n");
    if( pPager->useJournal && !pPager->tempFile ){
      rc = pager_open_journal(pPager);
    }
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2110 of file pager.c.

                                         {
  int rc;
  char zTemp[SQLITE_TEMPNAME_SIZE];
  if( !pPager->journalOpen ){
    pPager->ckptAutoopen = 1;
    return SQLITE_OK;
  }
  assert( pPager->journalOpen );
  assert( !pPager->ckptInUse );
  pPager->aInCkpt = sqliteMalloc( pPager->dbSize/8 + 1 );
  if( pPager->aInCkpt==0 ){
    sqliteOsReadLock(&pPager->fd);
    return SQLITE_NOMEM;
  }
#ifndef NDEBUG
  rc = sqliteOsFileSize(&pPager->jfd, &pPager->ckptJSize);
  if( rc ) goto ckpt_begin_failed;
  assert( pPager->ckptJSize == 
    pPager->nRec*JOURNAL_PG_SZ(journal_format)+JOURNAL_HDR_SZ(journal_format) );
#endif
  pPager->ckptJSize = pPager->nRec*JOURNAL_PG_SZ(journal_format)
                         + JOURNAL_HDR_SZ(journal_format);
  pPager->ckptSize = pPager->dbSize;
  if( !pPager->ckptOpen ){
    rc = sqlitepager_opentemp(zTemp, &pPager->cpfd);
    if( rc ) goto ckpt_begin_failed;
    pPager->ckptOpen = 1;
    pPager->ckptNRec = 0;
  }
  pPager->ckptInUse = 1;
  return SQLITE_OK;
 
ckpt_begin_failed:
  if( pPager->aInCkpt ){
    sqliteFree(pPager->aInCkpt);
    pPager->aInCkpt = 0;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2153 of file pager.c.

                                          {
  if( pPager->ckptInUse ){
    PgHdr *pPg, *pNext;
    sqliteOsSeek(&pPager->cpfd, 0);
    /* sqliteOsTruncate(&pPager->cpfd, 0); */
    pPager->ckptNRec = 0;
    pPager->ckptInUse = 0;
    sqliteFree( pPager->aInCkpt );
    pPager->aInCkpt = 0;
    for(pPg=pPager->pCkpt; pPg; pPg=pNext){
      pNext = pPg->pNextCkpt;
      assert( pPg->inCkpt );
      pPg->inCkpt = 0;
      pPg->pPrevCkpt = pPg->pNextCkpt = 0;
    }
    pPager->pCkpt = 0;
  }
  pPager->ckptAutoopen = 0;
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2177 of file pager.c.

                                            {
  int rc;
  if( pPager->ckptInUse ){
    rc = pager_ckpt_playback(pPager);
    sqlitepager_ckpt_commit(pPager);
  }else{
    rc = SQLITE_OK;
  }
  pPager->ckptAutoopen = 0;
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_close ( Pager pPager)

Definition at line 1067 of file pager.c.

                                    {
  PgHdr *pPg, *pNext;
  switch( pPager->state ){
    case SQLITE_WRITELOCK: {
      sqlitepager_rollback(pPager);
      sqliteOsUnlock(&pPager->fd);
      assert( pPager->journalOpen==0 );
      break;
    }
    case SQLITE_READLOCK: {
      sqliteOsUnlock(&pPager->fd);
      break;
    }
    default: {
      /* Do nothing */
      break;
    }
  }
  for(pPg=pPager->pAll; pPg; pPg=pNext){
    pNext = pPg->pNextAll;
    sqliteFree(pPg);
  }
  sqliteOsClose(&pPager->fd);
  assert( pPager->journalOpen==0 );
  /* Temp files are automatically deleted by the OS
  ** if( pPager->tempFile ){
  **   sqliteOsDelete(pPager->zFilename);
  ** }
  */
  CLR_PAGER(pPager);
  if( pPager->zFilename!=(char*)&pPager[1] ){
    assert( 0 );  /* Cannot happen */
    sqliteFree(pPager->zFilename);
    sqliteFree(pPager->zJournal);
    sqliteFree(pPager->zDirectory);
  }
  sqliteFree(pPager);
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_commit ( Pager pPager)

Definition at line 1986 of file pager.c.

                                     {
  int rc;
  PgHdr *pPg;

  if( pPager->errMask==PAGER_ERR_FULL ){
    rc = sqlitepager_rollback(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
    return rc;
  }
  if( pPager->errMask!=0 ){
    rc = pager_errcode(pPager);
    return rc;
  }
  if( pPager->state!=SQLITE_WRITELOCK ){
    return SQLITE_ERROR;
  }
  TRACE1("COMMIT\n");
  if( pPager->dirtyFile==0 ){
    /* Exit early (without doing the time-consuming sqliteOsSync() calls)
    ** if there have been no changes to the database file. */
    assert( pPager->needSync==0 );
    rc = pager_unwritelock(pPager);
    pPager->dbSize = -1;
    return rc;
  }
  assert( pPager->journalOpen );
  rc = syncJournal(pPager);
  if( rc!=SQLITE_OK ){
    goto commit_abort;
  }
  pPg = pager_get_all_dirty_pages(pPager);
  if( pPg ){
    rc = pager_write_pagelist(pPg);
    if( rc || (!pPager->noSync && sqliteOsSync(&pPager->fd)!=SQLITE_OK) ){
      goto commit_abort;
    }
  }
  rc = pager_unwritelock(pPager);
  pPager->dbSize = -1;
  return rc;

  /* Jump here if anything goes wrong during the commit process.
  */
commit_abort:
  rc = sqlitepager_rollback(pPager);
  if( rc==SQLITE_OK ){
    rc = SQLITE_FULL;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sqlitepager_dont_rollback ( void *  pData)

Definition at line 1955 of file pager.c.

                                           {
  PgHdr *pPg = DATA_TO_PGHDR(pData);
  Pager *pPager = pPg->pPager;

  if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return;
  if( pPg->alwaysRollback || pPager->alwaysRollback ) return;
  if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
    assert( pPager->aInJournal!=0 );
    pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
    pPg->inJournal = 1;
    if( pPager->ckptInUse ){
      pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
      page_add_to_ckpt_list(pPg);
    }
    TRACE2("DONT_ROLLBACK %d\n", pPg->pgno);
  }
  if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
    assert( pPager->aInCkpt!=0 );
    pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
    page_add_to_ckpt_list(pPg);
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sqlitepager_dont_write ( Pager pPager,
Pgno  pgno 
)

Definition at line 1927 of file pager.c.

                                                     {
  PgHdr *pPg;

  pPg = pager_lookup(pPager, pgno);
  pPg->alwaysRollback = 1;
  if( pPg && pPg->dirty && !pPager->ckptInUse ){
    if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
      /* If this pages is the last page in the file and the file has grown
      ** during the current transaction, then do NOT mark the page as clean.
      ** When the database file grows, we must make sure that the last page
      ** gets written at least once so that the disk file will be the correct
      ** size. If you do not write this page and the size of the file
      ** on the disk ends up being too small, that can lead to database
      ** corruption during the next transaction.
      */
    }else{
      TRACE2("DONT_WRITE %d\n", pgno);
      pPg->dirty = 0;
    }
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* sqlitepager_filename ( Pager pPager)

Definition at line 2192 of file pager.c.

                                               {
  return pPager->zFilename;
}

Here is the caller graph for this function:

int sqlitepager_get ( Pager pPager,
Pgno  pgno,
void **  ppPage 
)

Definition at line 1311 of file pager.c.

                                                            {
  PgHdr *pPg;
  int rc;

  /* Make sure we have not hit any critical errors.
  */ 
  assert( pPager!=0 );
  assert( pgno!=0 );
  *ppPage = 0;
  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
    return pager_errcode(pPager);
  }

  /* If this is the first page accessed, then get a read lock
  ** on the database file.
  */
  if( pPager->nRef==0 ){
    rc = sqliteOsReadLock(&pPager->fd);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pPager->state = SQLITE_READLOCK;

    /* If a journal file exists, try to play it back.
    */
    if( pPager->useJournal && sqliteOsFileExists(pPager->zJournal) ){
       int rc;

       /* Get a write lock on the database
       */
       rc = sqliteOsWriteLock(&pPager->fd);
       if( rc!=SQLITE_OK ){
         if( sqliteOsUnlock(&pPager->fd)!=SQLITE_OK ){
           /* This should never happen! */
           rc = SQLITE_INTERNAL;
         }
         return rc;
       }
       pPager->state = SQLITE_WRITELOCK;

       /* Open the journal for reading only.  Return SQLITE_BUSY if
       ** we are unable to open the journal file. 
       **
       ** The journal file does not need to be locked itself.  The
       ** journal file is never open unless the main database file holds
       ** a write lock, so there is never any chance of two or more
       ** processes opening the journal at the same time.
       */
       rc = sqliteOsOpenReadOnly(pPager->zJournal, &pPager->jfd);
       if( rc!=SQLITE_OK ){
         rc = sqliteOsUnlock(&pPager->fd);
         assert( rc==SQLITE_OK );
         return SQLITE_BUSY;
       }
       pPager->journalOpen = 1;
       pPager->journalStarted = 0;

       /* Playback and delete the journal.  Drop the database write
       ** lock and reacquire the read lock.
       */
       rc = pager_playback(pPager, 0);
       if( rc!=SQLITE_OK ){
         return rc;
       }
    }
    pPg = 0;
  }else{
    /* Search for page in cache */
    pPg = pager_lookup(pPager, pgno);
  }
  if( pPg==0 ){
    /* The requested page is not in the page cache. */
    int h;
    pPager->nMiss++;
    if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 ){
      /* Create a new page */
      pPg = sqliteMallocRaw( sizeof(*pPg) + SQLITE_PAGE_SIZE 
                              + sizeof(u32) + pPager->nExtra );
      if( pPg==0 ){
        pager_unwritelock(pPager);
        pPager->errMask |= PAGER_ERR_MEM;
        return SQLITE_NOMEM;
      }
      memset(pPg, 0, sizeof(*pPg));
      pPg->pPager = pPager;
      pPg->pNextAll = pPager->pAll;
      if( pPager->pAll ){
        pPager->pAll->pPrevAll = pPg;
      }
      pPg->pPrevAll = 0;
      pPager->pAll = pPg;
      pPager->nPage++;
    }else{
      /* Find a page to recycle.  Try to locate a page that does not
      ** require us to do an fsync() on the journal.
      */
      pPg = pPager->pFirstSynced;

      /* If we could not find a page that does not require an fsync()
      ** on the journal file then fsync the journal file.  This is a
      ** very slow operation, so we work hard to avoid it.  But sometimes
      ** it can't be helped.
      */
      if( pPg==0 ){
        int rc = syncJournal(pPager);
        if( rc!=0 ){
          sqlitepager_rollback(pPager);
          return SQLITE_IOERR;
        }
        pPg = pPager->pFirst;
      }
      assert( pPg->nRef==0 );

      /* Write the page to the database file if it is dirty.
      */
      if( pPg->dirty ){
        assert( pPg->needSync==0 );
        pPg->pDirty = 0;
        rc = pager_write_pagelist( pPg );
        if( rc!=SQLITE_OK ){
          sqlitepager_rollback(pPager);
          return SQLITE_IOERR;
        }
      }
      assert( pPg->dirty==0 );

      /* If the page we are recycling is marked as alwaysRollback, then
      ** set the global alwaysRollback flag, thus disabling the
      ** sqlite_dont_rollback() optimization for the rest of this transaction.
      ** It is necessary to do this because the page marked alwaysRollback
      ** might be reloaded at a later time but at that point we won't remember
      ** that is was marked alwaysRollback.  This means that all pages must
      ** be marked as alwaysRollback from here on out.
      */
      if( pPg->alwaysRollback ){
        pPager->alwaysRollback = 1;
      }

      /* Unlink the old page from the free list and the hash table
      */
      if( pPg==pPager->pFirstSynced ){
        PgHdr *p = pPg->pNextFree;
        while( p && p->needSync ){ p = p->pNextFree; }
        pPager->pFirstSynced = p;
      }
      if( pPg->pPrevFree ){
        pPg->pPrevFree->pNextFree = pPg->pNextFree;
      }else{
        assert( pPager->pFirst==pPg );
        pPager->pFirst = pPg->pNextFree;
      }
      if( pPg->pNextFree ){
        pPg->pNextFree->pPrevFree = pPg->pPrevFree;
      }else{
        assert( pPager->pLast==pPg );
        pPager->pLast = pPg->pPrevFree;
      }
      pPg->pNextFree = pPg->pPrevFree = 0;
      if( pPg->pNextHash ){
        pPg->pNextHash->pPrevHash = pPg->pPrevHash;
      }
      if( pPg->pPrevHash ){
        pPg->pPrevHash->pNextHash = pPg->pNextHash;
      }else{
        h = pager_hash(pPg->pgno);
        assert( pPager->aHash[h]==pPg );
        pPager->aHash[h] = pPg->pNextHash;
      }
      pPg->pNextHash = pPg->pPrevHash = 0;
      pPager->nOvfl++;
    }
    pPg->pgno = pgno;
    if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
      sqliteCheckMemory(pPager->aInJournal, pgno/8);
      assert( pPager->journalOpen );
      pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0;
      pPg->needSync = 0;
    }else{
      pPg->inJournal = 0;
      pPg->needSync = 0;
    }
    if( pPager->aInCkpt && (int)pgno<=pPager->ckptSize
             && (pPager->aInCkpt[pgno/8] & (1<<(pgno&7)))!=0 ){
      page_add_to_ckpt_list(pPg);
    }else{
      page_remove_from_ckpt_list(pPg);
    }
    pPg->dirty = 0;
    pPg->nRef = 1;
    REFINFO(pPg);
    pPager->nRef++;
    h = pager_hash(pgno);
    pPg->pNextHash = pPager->aHash[h];
    pPager->aHash[h] = pPg;
    if( pPg->pNextHash ){
      assert( pPg->pNextHash->pPrevHash==0 );
      pPg->pNextHash->pPrevHash = pPg;
    }
    if( pPager->nExtra>0 ){
      memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
    }
    if( pPager->dbSize<0 ) sqlitepager_pagecount(pPager);
    if( pPager->errMask!=0 ){
      sqlitepager_unref(PGHDR_TO_DATA(pPg));
      rc = pager_errcode(pPager);
      return rc;
    }
    if( pPager->dbSize<(int)pgno ){
      memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
    }else{
      int rc;
      sqliteOsSeek(&pPager->fd, (pgno-1)*(off_t)SQLITE_PAGE_SIZE);
      rc = sqliteOsRead(&pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
      TRACE2("FETCH %d\n", pPg->pgno);
      CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
      if( rc!=SQLITE_OK ){
        off_t fileSize;
        if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
               || fileSize>=pgno*SQLITE_PAGE_SIZE ){
          sqlitepager_unref(PGHDR_TO_DATA(pPg));
          return rc;
        }else{
          memset(PGHDR_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
        }
      }
    }
  }else{
    /* The requested page is in the page cache. */
    pPager->nHit++;
    page_ref(pPg);
  }
  *ppPage = PGHDR_TO_DATA(pPg);
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2082 of file pager.c.

                                         {
  return pPager->readOnly;
}

Here is the caller graph for this function:

int sqlitepager_iswriteable ( void *  pData)

Definition at line 1879 of file pager.c.

                                        {
  PgHdr *pPg = DATA_TO_PGHDR(pData);
  return pPg->dirty;
}

Here is the caller graph for this function:

void* sqlitepager_lookup ( Pager pPager,
Pgno  pgno 
)

Definition at line 1557 of file pager.c.

                                                  {
  PgHdr *pPg;

  assert( pPager!=0 );
  assert( pgno!=0 );
  if( pPager->errMask & ~(PAGER_ERR_FULL) ){
    return 0;
  }
  /* if( pPager->nRef==0 ){
  **  return 0;
  ** }
  */
  pPg = pager_lookup(pPager, pgno);
  if( pPg==0 ) return 0;
  page_ref(pPg);
  return PGHDR_TO_DATA(pPg);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_open ( Pager **  ppPager,
const char *  zFilename,
int  mxPage,
int  nExtra,
int  useJournal 
)

Definition at line 916 of file pager.c.

 {
  Pager *pPager;
  char *zFullPathname;
  int nameLen;
  OsFile fd;
  int rc, i;
  int tempFile;
  int readOnly = 0;
  char zTemp[SQLITE_TEMPNAME_SIZE];

  *ppPager = 0;
  if( sqlite_malloc_failed ){
    return SQLITE_NOMEM;
  }
  if( zFilename && zFilename[0] ){
    zFullPathname = sqliteOsFullPathname(zFilename);
    rc = sqliteOsOpenReadWrite(zFullPathname, &fd, &readOnly);
    tempFile = 0;
  }else{
    rc = sqlitepager_opentemp(zTemp, &fd);
    zFilename = zTemp;
    zFullPathname = sqliteOsFullPathname(zFilename);
    tempFile = 1;
  }
  if( sqlite_malloc_failed ){
    return SQLITE_NOMEM;
  }
  if( rc!=SQLITE_OK ){
    sqliteFree(zFullPathname);
    return SQLITE_CANTOPEN;
  }
  nameLen = strlen(zFullPathname);
  pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
  if( pPager==0 ){
    sqliteOsClose(&fd);
    sqliteFree(zFullPathname);
    return SQLITE_NOMEM;
  }
  SET_PAGER(pPager);
  pPager->zFilename = (char*)&pPager[1];
  pPager->zDirectory = &pPager->zFilename[nameLen+1];
  pPager->zJournal = &pPager->zDirectory[nameLen+1];
  strcpy(pPager->zFilename, zFullPathname);
  strcpy(pPager->zDirectory, zFullPathname);
  for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){}
  if( i>0 ) pPager->zDirectory[i-1] = 0;
  strcpy(pPager->zJournal, zFullPathname);
  sqliteFree(zFullPathname);
  strcpy(&pPager->zJournal[nameLen], "-journal");
  pPager->fd = fd;
  pPager->journalOpen = 0;
  pPager->useJournal = useJournal;
  pPager->ckptOpen = 0;
  pPager->ckptInUse = 0;
  pPager->nRef = 0;
  pPager->dbSize = -1;
  pPager->ckptSize = 0;
  pPager->ckptJSize = 0;
  pPager->nPage = 0;
  pPager->mxPage = mxPage>5 ? mxPage : 10;
  pPager->state = SQLITE_UNLOCK;
  pPager->errMask = 0;
  pPager->tempFile = tempFile;
  pPager->readOnly = readOnly;
  pPager->needSync = 0;
  pPager->noSync = pPager->tempFile || !useJournal;
  pPager->pFirst = 0;
  pPager->pFirstSynced = 0;
  pPager->pLast = 0;
  pPager->nExtra = nExtra;
  memset(pPager->aHash, 0, sizeof(pPager->aHash));
  *ppPager = pPager;
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int sqlitepager_opentemp ( char *  zFile,
OsFile fd 
) [static]

Definition at line 895 of file pager.c.

                                                        {
  int cnt = 8;
  int rc;
  do{
    cnt--;
    sqliteOsTempFileName(zFile);
    rc = sqliteOsOpenExclusive(zFile, fd, 1);
  }while( cnt>0 && rc!=SQLITE_OK );
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_overwrite ( Pager pPager,
Pgno  pgno,
void *  pData 
)

Definition at line 1888 of file pager.c.

                                                                {
  void *pPage;
  int rc;

  rc = sqlitepager_get(pPager, pgno, &pPage);
  if( rc==SQLITE_OK ){
    rc = sqlitepager_write(pPage);
    if( rc==SQLITE_OK ){
      memcpy(pPage, pData, SQLITE_PAGE_SIZE);
    }
    sqlitepager_unref(pPage);
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1013 of file pager.c.

                                        {
  off_t n;
  assert( pPager!=0 );
  if( pPager->dbSize>=0 ){
    return pPager->dbSize;
  }
  if( sqliteOsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
    pPager->errMask |= PAGER_ERR_DISK;
    return 0;
  }
  n /= SQLITE_PAGE_SIZE;
  if( pPager->state!=SQLITE_UNLOCK ){
    pPager->dbSize = n;
  }
  return n;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Pgno sqlitepager_pagenumber ( void *  pData)

Definition at line 1110 of file pager.c.

                                        {
  PgHdr *p = DATA_TO_PGHDR(pData);
  return p->pgno;
}

Here is the caller graph for this function:

int sqlitepager_ref ( void *  pData)

Definition at line 1149 of file pager.c.

                                {
  PgHdr *pPg = DATA_TO_PGHDR(pData);
  page_ref(pPg);
  return SQLITE_OK;
}

Here is the caller graph for this function:

Definition at line 2051 of file pager.c.

                                       {
  int rc;
  TRACE1("ROLLBACK\n");
  if( !pPager->dirtyFile || !pPager->journalOpen ){
    rc = pager_unwritelock(pPager);
    pPager->dbSize = -1;
    return rc;
  }

  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
    if( pPager->state>=SQLITE_WRITELOCK ){
      pager_playback(pPager, 1);
    }
    return pager_errcode(pPager);
  }
  if( pPager->state!=SQLITE_WRITELOCK ){
    return SQLITE_OK;
  }
  rc = pager_playback(pPager, 1);
  if( rc!=SQLITE_OK ){
    rc = SQLITE_CORRUPT;
    pPager->errMask |= PAGER_ERR_CORRUPT;
  }
  pPager->dbSize = -1;
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void sqlitepager_set_cachesize ( Pager pPager,
int  mxPage 
)

Definition at line 841 of file pager.c.

                                                         {
  if( mxPage>=0 ){
    pPager->noSync = pPager->tempFile;
    if( pPager->noSync==0 ) pPager->needSync = 0;
  }else{
    pPager->noSync = 1;
    mxPage = -mxPage;
  }
  if( mxPage>10 ){
    pPager->mxPage = mxPage;
  }
}

Here is the caller graph for this function:

void sqlitepager_set_codec ( Pager pPager,
void(*)(void *, void *, Pgno, int xCodec,
void *  pCodecArg 
)

Definition at line 2199 of file pager.c.

 {
  pPager->xCodec = xCodec;
  pPager->pCodecArg = pCodecArg;
}
void sqlitepager_set_destructor ( Pager pPager,
void(*)(void *)  xDesc 
)

Definition at line 1005 of file pager.c.

                                                                    {
  pPager->xDestructor = xDesc;
}

Here is the caller graph for this function:

void sqlitepager_set_safety_level ( Pager pPager,
int  level 
)

Definition at line 880 of file pager.c.

                                                           {
  pPager->noSync =  level==1 || pPager->tempFile;
  pPager->fullSync = level==3 && !pPager->tempFile;
  if( pPager->noSync==0 ) pPager->needSync = 0;
}

Here is the caller graph for this function:

int* sqlitepager_stats ( Pager pPager)

Definition at line 2089 of file pager.c.

                                     {
  static int a[9];
  a[0] = pPager->nRef;
  a[1] = pPager->nPage;
  a[2] = pPager->mxPage;
  a[3] = pPager->dbSize;
  a[4] = pPager->state;
  a[5] = pPager->errMask;
  a[6] = pPager->nHit;
  a[7] = pPager->nMiss;
  a[8] = pPager->nOvfl;
  return a;
}

Here is the caller graph for this function:

int sqlitepager_truncate ( Pager pPager,
Pgno  nPage 
)

Definition at line 1038 of file pager.c.

                                                   {
  int rc;
  if( pPager->dbSize<0 ){
    sqlitepager_pagecount(pPager);
  }
  if( pPager->errMask!=0 ){
    rc = pager_errcode(pPager);
    return rc;
  }
  if( nPage>=(unsigned)pPager->dbSize ){
    return SQLITE_OK;
  }
  syncJournal(pPager);
  rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage);
  if( rc==SQLITE_OK ){
    pPager->dbSize = nPage;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_unref ( void *  pData)

Definition at line 1583 of file pager.c.

                                  {
  PgHdr *pPg;

  /* Decrement the reference count for this page
  */
  pPg = DATA_TO_PGHDR(pData);
  assert( pPg->nRef>0 );
  pPg->nRef--;
  REFINFO(pPg);

  /* When the number of references to a page reach 0, call the
  ** destructor and add the page to the freelist.
  */
  if( pPg->nRef==0 ){
    Pager *pPager;
    pPager = pPg->pPager;
    pPg->pNextFree = 0;
    pPg->pPrevFree = pPager->pLast;
    pPager->pLast = pPg;
    if( pPg->pPrevFree ){
      pPg->pPrevFree->pNextFree = pPg;
    }else{
      pPager->pFirst = pPg;
    }
    if( pPg->needSync==0 && pPager->pFirstSynced==0 ){
      pPager->pFirstSynced = pPg;
    }
    if( pPager->xDestructor ){
      pPager->xDestructor(pData);
    }
  
    /* When all pages reach the freelist, drop the read lock from
    ** the database file.
    */
    pPager->nRef--;
    assert( pPager->nRef>=0 );
    if( pPager->nRef==0 ){
      pager_reset(pPager);
    }
  }
  return SQLITE_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int sqlitepager_write ( void *  pData)

Definition at line 1753 of file pager.c.

                                  {
  PgHdr *pPg = DATA_TO_PGHDR(pData);
  Pager *pPager = pPg->pPager;
  int rc = SQLITE_OK;

  /* Check for errors
  */
  if( pPager->errMask ){ 
    return pager_errcode(pPager);
  }
  if( pPager->readOnly ){
    return SQLITE_PERM;
  }

  /* Mark the page as dirty.  If the page has already been written
  ** to the journal then we can return right away.
  */
  pPg->dirty = 1;
  if( pPg->inJournal && (pPg->inCkpt || pPager->ckptInUse==0) ){
    pPager->dirtyFile = 1;
    return SQLITE_OK;
  }

  /* If we get this far, it means that the page needs to be
  ** written to the transaction journal or the ckeckpoint journal
  ** or both.
  **
  ** First check to see that the transaction journal exists and
  ** create it if it does not.
  */
  assert( pPager->state!=SQLITE_UNLOCK );
  rc = sqlitepager_begin(pData);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  assert( pPager->state==SQLITE_WRITELOCK );
  if( !pPager->journalOpen && pPager->useJournal ){
    rc = pager_open_journal(pPager);
    if( rc!=SQLITE_OK ) return rc;
  }
  assert( pPager->journalOpen || !pPager->useJournal );
  pPager->dirtyFile = 1;

  /* The transaction journal now exists and we have a write lock on the
  ** main database file.  Write the current page to the transaction 
  ** journal if it is not there already.
  */
  if( !pPg->inJournal && pPager->useJournal ){
    if( (int)pPg->pgno <= pPager->origDbSize ){
      int szPg;
      u32 saved;
      if( journal_format>=JOURNAL_FORMAT_3 ){
        u32 cksum = pager_cksum(pPager, pPg->pgno, pData);
        saved = *(u32*)PGHDR_TO_EXTRA(pPg);
        store32bits(cksum, pPg, SQLITE_PAGE_SIZE);
        szPg = SQLITE_PAGE_SIZE+8;
      }else{
        szPg = SQLITE_PAGE_SIZE+4;
      }
      store32bits(pPg->pgno, pPg, -4);
      CODEC(pPager, pData, pPg->pgno, 7);
      rc = sqliteOsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
      TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync);
      CODEC(pPager, pData, pPg->pgno, 0);
      if( journal_format>=JOURNAL_FORMAT_3 ){
        *(u32*)PGHDR_TO_EXTRA(pPg) = saved;
      }
      if( rc!=SQLITE_OK ){
        sqlitepager_rollback(pPager);
        pPager->errMask |= PAGER_ERR_FULL;
        return rc;
      }
      pPager->nRec++;
      assert( pPager->aInJournal!=0 );
      pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
      pPg->needSync = !pPager->noSync;
      pPg->inJournal = 1;
      if( pPager->ckptInUse ){
        pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
        page_add_to_ckpt_list(pPg);
      }
    }else{
      pPg->needSync = !pPager->journalStarted && !pPager->noSync;
      TRACE3("APPEND %d %d\n", pPg->pgno, pPg->needSync);
    }
    if( pPg->needSync ){
      pPager->needSync = 1;
    }
  }

  /* If the checkpoint journal is open and the page is not in it,
  ** then write the current page to the checkpoint journal.  Note that
  ** the checkpoint journal always uses the simplier format 2 that lacks
  ** checksums.  The header is also omitted from the checkpoint journal.
  */
  if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
    assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
    store32bits(pPg->pgno, pPg, -4);
    CODEC(pPager, pData, pPg->pgno, 7);
    rc = sqliteOsWrite(&pPager->cpfd, &((char*)pData)[-4], SQLITE_PAGE_SIZE+4);
    TRACE2("CKPT-JOURNAL %d\n", pPg->pgno);
    CODEC(pPager, pData, pPg->pgno, 0);
    if( rc!=SQLITE_OK ){
      sqlitepager_rollback(pPager);
      pPager->errMask |= PAGER_ERR_FULL;
      return rc;
    }
    pPager->ckptNRec++;
    assert( pPager->aInCkpt!=0 );
    pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
    page_add_to_ckpt_list(pPg);
  }

  /* Update the database size and return.
  */
  if( pPager->dbSize<(int)pPg->pgno ){
    pPager->dbSize = pPg->pgno;
  }
  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void store32bits ( u32  val,
PgHdr p,
int  offset 
) [static]

Definition at line 356 of file pager.c.

                                                      {
  unsigned char *ac;
  ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
  if( journal_format<=1 ){
    memcpy(ac, &val, 4);
  }else{
    ac[0] = (val>>24) & 0xff;
    ac[1] = (val>>16) & 0xff;
    ac[2] = (val>>8) & 0xff;
    ac[3] = val & 0xff;
  }
}

Here is the caller graph for this function:

static int syncJournal ( Pager pPager) [static]

Definition at line 1175 of file pager.c.

                                     {
  PgHdr *pPg;
  int rc = SQLITE_OK;

  /* Sync the journal before modifying the main database
  ** (assuming there is a journal and it needs to be synced.)
  */
  if( pPager->needSync ){
    if( !pPager->tempFile ){
      assert( pPager->journalOpen );
      /* assert( !pPager->noSync ); // noSync might be set if synchronous
      ** was turned off after the transaction was started.  Ticket #615 */
#ifndef NDEBUG
      {
        /* Make sure the pPager->nRec counter we are keeping agrees
        ** with the nRec computed from the size of the journal file.
        */
        off_t hdrSz, pgSz, jSz;
        hdrSz = JOURNAL_HDR_SZ(journal_format);
        pgSz = JOURNAL_PG_SZ(journal_format);
        rc = sqliteOsFileSize(&pPager->jfd, &jSz);
        if( rc!=0 ) return rc;
        assert( pPager->nRec*pgSz+hdrSz==jSz );
      }
#endif
      if( journal_format>=3 ){
        /* Write the nRec value into the journal file header */
        off_t szJ;
        if( pPager->fullSync ){
          TRACE1("SYNC\n");
          rc = sqliteOsSync(&pPager->jfd);
          if( rc!=0 ) return rc;
        }
        sqliteOsSeek(&pPager->jfd, sizeof(aJournalMagic1));
        rc = write32bits(&pPager->jfd, pPager->nRec);
        if( rc ) return rc;
        szJ = JOURNAL_HDR_SZ(journal_format) +
                 pPager->nRec*JOURNAL_PG_SZ(journal_format);
        sqliteOsSeek(&pPager->jfd, szJ);
      }
      TRACE1("SYNC\n");
      rc = sqliteOsSync(&pPager->jfd);
      if( rc!=0 ) return rc;
      pPager->journalStarted = 1;
    }
    pPager->needSync = 0;

    /* Erase the needSync flag from every page.
    */
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      pPg->needSync = 0;
    }
    pPager->pFirstSynced = pPager->pFirst;
  }

#ifndef NDEBUG
  /* If the Pager.needSync flag is clear then the PgHdr.needSync
  ** flag must also be clear for all pages.  Verify that this
  ** invariant is true.
  */
  else{
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      assert( pPg->needSync==0 );
    }
    assert( pPager->pFirstSynced==pPager->pFirst );
  }
#endif

  return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int write32bits ( OsFile fd,
u32  val 
) [static]

Definition at line 337 of file pager.c.

                                           {
  unsigned char ac[4];
  if( journal_format<=1 ){
    return sqliteOsWrite(fd, &val, 4);
  }
  ac[0] = (val>>24) & 0xff;
  ac[1] = (val>>16) & 0xff;
  ac[2] = (val>>8) & 0xff;
  ac[3] = val & 0xff;
  return sqliteOsWrite(fd, ac, 4);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const unsigned char aJournalMagic1[] [static]
Initial value:
 {
  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd4,
}

Definition at line 249 of file pager.c.

const unsigned char aJournalMagic2[] [static]
Initial value:
 {
  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd5,
}

Definition at line 252 of file pager.c.

const unsigned char aJournalMagic3[] [static]
Initial value:
 {
  0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd6,
}

Definition at line 255 of file pager.c.