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

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

Overview
Comment:Simplifications and comment improvements in pager.c. (CVS 6926)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2d2f42ca0a24ed8b33f9ad560c76a6c1301c757b
User & Date: drh 2009-07-24 12:35:57
Context
2009-07-24
16:32
Simplifications to pager.c in support of structural coverage testing. (CVS 6927) check-in: 7222ad26 user: drh tags: trunk
12:35
Simplifications and comment improvements in pager.c. (CVS 6926) check-in: 2d2f42ca user: drh tags: trunk
2009-07-23
01:44
Simplifications and comment enhancements on btree.c. (CVS 6925) check-in: 5ba880dd user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/pager.c.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
....
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
....
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
....
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527



4528
4529
4530
4531
4532
4533
4534
....
4581
4582
4583
4584
4585
4586
4587
4588


4589
4590
4591
4592
4593
4594

4595
4596

4597
4598
4599
4600
4601
4602
4603
4604
4605
....
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
....
4748
4749
4750
4751
4752
4753
4754
4755
4756

4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.613 2009/07/22 16:41:15 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
    ** starting at pg1, then it needs to be set for all of them. Because
    ** writing to any of these nPage pages may damage the others, the
    ** journal file must contain sync()ed copies of all of them
    ** before any of them can be written out to the database file.
    */
    if( rc==SQLITE_OK && needSync ){
      assert( !MEMDB && pPager->noSync==0 );
      for(ii=0; ii<nPage && needSync; ii++){
        PgHdr *pPage = pager_lookup(pPager, pg1+ii);
        if( pPage ){
          pPage->flags |= PGHDR_NEED_SYNC;
          sqlite3PagerUnref(pPage);
        }
      }
      assert(pPager->needSync);
................................................................................
}

/*
** This routine is called to increment the value of the database file 
** change-counter, stored as a 4-byte big-endian integer starting at 
** byte offset 24 of the pager file.
**
** If the isDirect flag is zero, then this is done by calling 
** sqlite3PagerWrite() on page 1, then modifying the contents of the
** page data. In this case the file will be updated when the current
** transaction is committed.
**
** The isDirect flag may only be non-zero if the library was compiled
** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
** if isDirect is non-zero, then the database file is updated directly
** by writing an updated version of page 1 using a call to the 
** sqlite3OsWrite() function.
*/
static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
  int rc = SQLITE_OK;
................................................................................
  **
  ** The idea is that if the atomic-write optimization is not
  ** enabled at compile time, the compiler can omit the tests of
  ** 'isDirect' below, as well as the block enclosed in the
  ** "if( isDirect )" condition.
  */
#ifndef SQLITE_ENABLE_ATOMIC_WRITE
  const int isDirect = 0;
  assert( isDirectMode==0 );
  UNUSED_PARAMETER(isDirectMode);
#else
  const int isDirect = isDirectMode;
#endif

  assert( pPager->state>=PAGER_RESERVED );
  if( !pPager->changeCountDone && pPager->dbSize>0 ){
    PgHdr *pPgHdr;                /* Reference to page 1 */
    u32 change_counter;           /* Initial value of change-counter field */

................................................................................
    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    assert( pPgHdr==0 || rc==SQLITE_OK );

    /* If page one was fetched successfully, and this function is not
    ** operating in direct-mode, make page 1 writable.
    */
    if( rc==SQLITE_OK && !isDirect ){
      rc = sqlite3PagerWrite(pPgHdr);
    }

    if( rc==SQLITE_OK ){
      /* Increment the value just read and write it back to byte 24. */
      change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
      change_counter++;
      put32bits(((char*)pPgHdr->pData)+24, change_counter);

      /* If running in direct mode, write the contents of page 1 to the file. */
      if( isDirect ){
        const void *zBuf = pPgHdr->pData;
        assert( pPager->dbFileSize>0 );
        rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);
      }

      /* If everything worked, set the changeCountDone flag. */
      if( rc==SQLITE_OK ){



        pPager->changeCountDone = 1;
      }
    }

    /* Release the page reference. */
    sqlite3PagerUnref(pPgHdr);
  }
................................................................................
int sqlite3PagerCommitPhaseOne(
  Pager *pPager,                  /* Pager object */
  const char *zMaster,            /* If not NULL, the master journal name */
  int noSync                      /* True to omit the xSync on the db file */
){
  int rc = SQLITE_OK;             /* Return code */

  if( pPager->errCode ){


    return pPager->errCode;
  }

  PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 
      pPager->zFilename, zMaster, pPager->dbSize));


  /* If this is an in-memory db, or no pages have been written to, or this
  ** function has already been called, it is a no-op.

  */
  if( MEMDB && pPager->dbModified ){
    sqlite3BackupRestart(pPager->pBackup);
  }else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){

    /* The following block updates the change-counter. Exactly how it
    ** does this depends on whether or not the atomic-update optimization
    ** was enabled at compile time, and if this transaction meets the 
    ** runtime criteria to use the operation: 
................................................................................
    }
    IOTRACE(("DBSYNC %p\n", pPager))

    pPager->state = PAGER_SYNCED;
  }

commit_phase_one_exit:
  if( rc==SQLITE_IOERR_BLOCKED ){
    /* pager_incr_changecounter() may attempt to obtain an exclusive
    ** lock to spill the cache and return IOERR_BLOCKED. But since 
    ** there is no chance the cache is inconsistent, it is
    ** better to return SQLITE_BUSY.
    **/
    rc = SQLITE_BUSY;
  }
  return rc;
}


/*
** When this function is called, the database file has been completely
** updated to reflect the changes made by the current transaction and
................................................................................
**
** If an error occurs, an IO error code is returned and the pager
** moves into the error state. Otherwise, SQLITE_OK is returned.
*/
int sqlite3PagerCommitPhaseTwo(Pager *pPager){
  int rc = SQLITE_OK;                  /* Return code */

  /* Do not proceed if the pager is already in the error state. */
  if( pPager->errCode ){

    return pPager->errCode;
  }

  /* This function should not be called if the pager is not in at least
  ** PAGER_RESERVED state. And indeed SQLite never does this. But it is
  ** nice to have this defensive block here anyway.
  */
  if( NEVER(pPager->state<PAGER_RESERVED) ){
    return SQLITE_ERROR;
  }

  /* An optimization. If the database was not actually modified during
  ** this transaction, the pager is running in exclusive-mode and is
  ** using persistent journals, then this function is a no-op.
  **
  ** The start of the journal file currently contains a single journal 
  ** header with the nRec field set to 0. If such a journal is used as







|







 







|







 







|




|







 







|



|







 







|










|



<
<
<
|
>
>
>







 







|
>
>
|
<




>
|
|
>
|
<







 







<
<
<
<
<
<
<
<







 







|
|
>
|
<



|

|
<
<







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
....
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
....
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
....
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523



4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
....
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591

4592
4593
4594
4595
4596
4597
4598
4599
4600

4601
4602
4603
4604
4605
4606
4607
....
4720
4721
4722
4723
4724
4725
4726








4727
4728
4729
4730
4731
4732
4733
....
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752

4753
4754
4755
4756
4757
4758


4759
4760
4761
4762
4763
4764
4765
** The pager is used to access a database disk file.  It implements
** atomic commit and rollback through the use of a journal file that
** is separate from the database file.  The pager also implements file
** locking to prevent two processes from writing the same database
** file simultaneously, or one process from reading the database while
** another is writing.
**
** @(#) $Id: pager.c,v 1.614 2009/07/24 12:35:57 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
    ** starting at pg1, then it needs to be set for all of them. Because
    ** writing to any of these nPage pages may damage the others, the
    ** journal file must contain sync()ed copies of all of them
    ** before any of them can be written out to the database file.
    */
    if( rc==SQLITE_OK && needSync ){
      assert( !MEMDB && pPager->noSync==0 );
      for(ii=0; ii<nPage; ii++){
        PgHdr *pPage = pager_lookup(pPager, pg1+ii);
        if( pPage ){
          pPage->flags |= PGHDR_NEED_SYNC;
          sqlite3PagerUnref(pPage);
        }
      }
      assert(pPager->needSync);
................................................................................
}

/*
** This routine is called to increment the value of the database file 
** change-counter, stored as a 4-byte big-endian integer starting at 
** byte offset 24 of the pager file.
**
** If the isDirectMode flag is zero, then this is done by calling 
** sqlite3PagerWrite() on page 1, then modifying the contents of the
** page data. In this case the file will be updated when the current
** transaction is committed.
**
** The isDirectMode flag may only be non-zero if the library was compiled
** with the SQLITE_ENABLE_ATOMIC_WRITE macro defined. In this case,
** if isDirect is non-zero, then the database file is updated directly
** by writing an updated version of page 1 using a call to the 
** sqlite3OsWrite() function.
*/
static int pager_incr_changecounter(Pager *pPager, int isDirectMode){
  int rc = SQLITE_OK;
................................................................................
  **
  ** The idea is that if the atomic-write optimization is not
  ** enabled at compile time, the compiler can omit the tests of
  ** 'isDirect' below, as well as the block enclosed in the
  ** "if( isDirect )" condition.
  */
#ifndef SQLITE_ENABLE_ATOMIC_WRITE
# define DIRECT_MODE 0
  assert( isDirectMode==0 );
  UNUSED_PARAMETER(isDirectMode);
#else
# define DIRECT_MODE isDirectMode
#endif

  assert( pPager->state>=PAGER_RESERVED );
  if( !pPager->changeCountDone && pPager->dbSize>0 ){
    PgHdr *pPgHdr;                /* Reference to page 1 */
    u32 change_counter;           /* Initial value of change-counter field */

................................................................................
    /* Open page 1 of the file for writing. */
    rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
    assert( pPgHdr==0 || rc==SQLITE_OK );

    /* If page one was fetched successfully, and this function is not
    ** operating in direct-mode, make page 1 writable.
    */
    if( rc==SQLITE_OK && !DIRECT_MODE ){
      rc = sqlite3PagerWrite(pPgHdr);
    }

    if( rc==SQLITE_OK ){
      /* Increment the value just read and write it back to byte 24. */
      change_counter = sqlite3Get4byte((u8*)pPager->dbFileVers);
      change_counter++;
      put32bits(((char*)pPgHdr->pData)+24, change_counter);

      /* If running in direct mode, write the contents of page 1 to the file. */
      if( DIRECT_MODE ){
        const void *zBuf = pPgHdr->pData;
        assert( pPager->dbFileSize>0 );
        rc = sqlite3OsWrite(pPager->fd, zBuf, pPager->pageSize, 0);



        if( rc==SQLITE_OK ){
          pPager->changeCountDone = 1;
        }
      }else{
        pPager->changeCountDone = 1;
      }
    }

    /* Release the page reference. */
    sqlite3PagerUnref(pPgHdr);
  }
................................................................................
int sqlite3PagerCommitPhaseOne(
  Pager *pPager,                  /* Pager object */
  const char *zMaster,            /* If not NULL, the master journal name */
  int noSync                      /* True to omit the xSync on the db file */
){
  int rc = SQLITE_OK;             /* Return code */

  /* If a prior error occurred, this routine should not be called.  ROLLBACK
  ** is the appropriate response to an error, not COMMIT.  Guard against
  ** coding errors by repeating the prior error. */
  if( NEVER(pPager->errCode) ) return pPager->errCode;


  PAGERTRACE(("DATABASE SYNC: File=%s zMaster=%s nSize=%d\n", 
      pPager->zFilename, zMaster, pPager->dbSize));

  if( MEMDB && pPager->dbModified ){
    /* If this is an in-memory db, or no pages have been written to, or this
    ** function has already been called, it is mostly a no-op.  However, any
    ** backup in progress needs to be restarted.
    */

    sqlite3BackupRestart(pPager->pBackup);
  }else if( pPager->state!=PAGER_SYNCED && pPager->dbModified ){

    /* The following block updates the change-counter. Exactly how it
    ** does this depends on whether or not the atomic-update optimization
    ** was enabled at compile time, and if this transaction meets the 
    ** runtime criteria to use the operation: 
................................................................................
    }
    IOTRACE(("DBSYNC %p\n", pPager))

    pPager->state = PAGER_SYNCED;
  }

commit_phase_one_exit:








  return rc;
}


/*
** When this function is called, the database file has been completely
** updated to reflect the changes made by the current transaction and
................................................................................
**
** If an error occurs, an IO error code is returned and the pager
** moves into the error state. Otherwise, SQLITE_OK is returned.
*/
int sqlite3PagerCommitPhaseTwo(Pager *pPager){
  int rc = SQLITE_OK;                  /* Return code */

  /* This routine should not be called if a prior error has occurred.
  ** But if (due to a coding error elsewhere in the system) it does get
  ** called, just return the same error code without doing anything. */
  if( NEVER(pPager->errCode) ) return pPager->errCode;


  /* This function should not be called if the pager is not in at least
  ** PAGER_RESERVED state. And indeed SQLite never does this. But it is
  ** nice to have this defensive test here anyway.
  */
  if( NEVER(pPager->state<PAGER_RESERVED) ) return SQLITE_ERROR;



  /* An optimization. If the database was not actually modified during
  ** this transaction, the pager is running in exclusive-mode and is
  ** using persistent journals, then this function is a no-op.
  **
  ** The start of the journal file currently contains a single journal 
  ** header with the nRec field set to 0. If such a journal is used as