/ Check-in [a7fd9e622b]
Login

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

Overview
Comment:Speed improvements for in-memory databases by omitting flag clearing on pages where it is impossible for the flag to be set and by avoiding assert()s on non-debugging builds. Ticket #3384. (CVS 5715)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: a7fd9e622bc1050e78f227ec42b6ba90c87c865a
User & Date: drh 2008-09-17 20:06:26
Context
2008-09-18
01:08
Performance improvements in getAndInitPage(): omit the upper bound check on page number if the page is already in cache. (CVS 5716) check-in: badd0873e6 user: drh tags: trunk
2008-09-17
20:06
Speed improvements for in-memory databases by omitting flag clearing on pages where it is impossible for the flag to be set and by avoiding assert()s on non-debugging builds. Ticket #3384. (CVS 5715) check-in: a7fd9e622b user: drh tags: trunk
16:14
Changes to test scripts to support running on symbian. (CVS 5714) check-in: 6ef34e9d31 user: danielk1977 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
...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
....
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
....
1757
1758
1759
1760
1761
1762
1763

1764
1765
1766
1767
1768
1769
1770
....
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
....
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
....
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
....
2841
2842
2843
2844
2845
2846
2847

2848
2849
2850
2851
2852
2853
2854
....
3389
3390
3391
3392
3393
3394
3395

3396
3397
3398
3399
3400
3401
3402
....
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
....
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
....
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
....
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
....
4128
4129
4130
4131
4132
4133
4134

4135
4136
4137
4138
4139
4140
4141
....
4170
4171
4172
4173
4174
4175
4176

4177
4178
4179
4180
4181
4182
4183
** 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.490 2008/09/16 05:12:24 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
    pPager->pInJournal = 0;
    sqlite3BitvecDestroy(pPager->pAlwaysRollback);
    pPager->pAlwaysRollback = 0;
    sqlite3PcacheCleanAll(pPager->pPCache);
#ifdef SQLITE_CHECK_PAGES
    sqlite3PcacheIterate(pPager->pPCache, pager_set_pagehash);
#endif
    sqlite3PcacheSetFlags(pPager->pPCache,
       ~(PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC), 0
    );
    pPager->dirtyCache = 0;
    pPager->nRec = 0;
  }else{
    assert( pPager->pInJournal==0 );
  }

................................................................................
**              point of causing damage to the database during rollback.
**
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){
  pPager->noSync =  level==1 || pPager->tempFile;
  pPager->fullSync = level==3 && !pPager->tempFile;
  pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
  if( pPager->noSync ) pPager->needSync = 0;
}
#endif

/*
................................................................................
    if( zPathname==0 ){
      return SQLITE_NOMEM;
    }
#ifndef SQLITE_OMIT_MEMORYDB
    if( strcmp(zFilename,":memory:")==0 ){
      memDb = 1;
      zPathname[0] = 0;

    }else
#endif
    {
      rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
    }
    if( rc!=SQLITE_OK ){
      sqlite3_free(zPathname);
................................................................................
    memcpy(pPager->zJournal, pPager->zFilename, nPathname);
    memcpy(&pPager->zJournal[nPathname], "-journal", 9);
  }else{
    pPager->zJournal = 0;
  }

  /* pPager->journalOpen = 0; */
  pPager->useJournal = useJournal && !memDb;
  pPager->noReadlock = noReadlock && readOnly;
  /* pPager->stmtOpen = 0; */
  /* pPager->stmtInUse = 0; */
  /* pPager->nRef = 0; */
  pPager->dbSize = memDb-1;
  pPager->pageSize = szPageDflt;
  /* pPager->stmtSize = 0; */
................................................................................
      }
      pPager->journalStarted = 1;
    }
    pPager->needSync = 0;

    /* Erase the needSync flag from every page.
    */
    sqlite3PcacheSetFlags(pPager->pPCache, ~PGHDR_NEED_SYNC, 0);
    /* lruListSetFirstSynced(pPager); */
  }

#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{
    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_NEED_SYNC);
    /* assert( pPager->lru.pFirstSynced==pPager->lru.pFirst ); */
  }
#endif

  return rc;
}

/*
................................................................................
      PAGERTRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
    }
#endif
    if( rc ) return rc;
#ifdef SQLITE_CHECK_PAGES
    pList->pageHash = pager_pagehash(pList);
#endif
    /* makeClean(pList); */
    pList = pList->pDirty;
  }

  /* sqlite3PcacheCleanAll(pPager->pPCache); */
  return SQLITE_OK;
}

/*
** This function is called by the pcache layer when it has reached some
** soft memory limit. The argument is a pointer to a purgeable Pager 
** object. This function attempts to make a single dirty page that has no
................................................................................
    /* The pager cache has created a new page. Its content needs to 
    ** be initialized.
    */
    int nMax;
    PAGER_INCR(pPager->nMiss);
    pPg->pPager = pPager;
    if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){

      pPg->flags |= PGHDR_IN_JOURNAL;
    }
    memset(pPg->pExtra, 0, pPager->nExtra);

    rc = sqlite3PagerPagecount(pPager, &nMax);
    if( rc!=SQLITE_OK ){
      sqlite3PagerUnref(pPg);
................................................................................
    /* If the PgHdr.needSync flag is set for any of the nPage pages 
    ** 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( needSync ){

      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);
    }
................................................................................
    assert( pPager->dirtyCache==0 || pPager->journalOpen==0 );
    return SQLITE_OK;
  }
  PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
  if( MEMDB ){
    sqlite3PcacheCommit(pPager->pPCache, 0);
    sqlite3PcacheCleanAll(pPager->pPCache);
    sqlite3PcacheSetFlags(pPager->pPCache, 
       ~(PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC), 0
    );
    pPager->state = PAGER_SHARED;
  }else{
    assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
    rc = pager_end_transaction(pPager, pPager->setMaster);
    rc = pager_error(pPager, rc);
  }
  return rc;
................................................................................
int sqlite3PagerRollback(Pager *pPager){
  int rc = SQLITE_OK;
  PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
  if( MEMDB ){
    sqlite3PcacheRollback(pPager->pPCache, 1);
    sqlite3PcacheRollback(pPager->pPCache, 0);
    sqlite3PcacheCleanAll(pPager->pPCache);
    sqlite3PcacheSetFlags(pPager->pPCache, 
       ~(PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC), 0
    );
    pPager->dbSize = pPager->origDbSize;
    pager_truncate_cache(pPager);
    pPager->stmtInUse = 0;
    pPager->state = PAGER_SHARED;
  }else if( !pPager->dirtyCache || !pPager->journalOpen ){
    rc = pager_end_transaction(pPager, pPager->setMaster);
  }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
................................................................................
/*
** Commit a statement.
*/
int sqlite3PagerStmtCommit(Pager *pPager){
  if( pPager->stmtInUse ){
    PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
    if( !MEMDB ){
      /* sqlite3OsTruncate(pPager->stfd, 0); */
      sqlite3BitvecDestroy(pPager->pInStmt);
      pPager->pInStmt = 0;
    }else{
      sqlite3PcacheCommit(pPager->pPCache, 1);
    }
    pPager->stmtNRec = 0;
    pPager->stmtInUse = 0;
................................................................................

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page pPg to location pgno in the file.
**
** There must be no references to the page previously located at
** pgno (which we call pPgOld) though that page is allowed to be
** in cache.  If the page previous located at pgno is not already
** in the rollback journal, it is not put there by by this routine.
**
** References to the page pPg remain valid. Updating any
** meta-data associated with pPg (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
** A transaction must be active when this routine is called. It used to be
................................................................................
  pPg->flags &= ~(PGHDR_NEED_SYNC|PGHDR_IN_JOURNAL);
  pPgOld = pager_lookup(pPager, pgno);
  assert( !pPgOld || pPgOld->nRef==1 );
  if( pPgOld ){
    pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
  }
  if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){

    pPg->flags |= PGHDR_IN_JOURNAL;
  }

  sqlite3PcacheMove(pPg, pgno);
  if( pPgOld ){
    sqlite3PcacheMove(pPgOld, 0);
    sqlite3PcacheRelease(pPgOld);
................................................................................
    if( rc!=SQLITE_OK ){
      if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
        sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
      }
      return rc;
    }
    pPager->needSync = 1;

    pPgHdr->flags |= PGHDR_NEED_SYNC;
    pPgHdr->flags |= PGHDR_IN_JOURNAL;
    makeDirty(pPgHdr);
    sqlite3PagerUnref(pPgHdr);
  }

  return SQLITE_OK;







|







 







|
|







 







|







 







>







 







|







 







|
<









<







 







<



<







 







>







 







>







 







|
<
<







 







|
<
<







 







<







 







|







 







>







 







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
....
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
....
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
....
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
....
2319
2320
2321
2322
2323
2324
2325
2326

2327
2328
2329
2330
2331
2332
2333
2334
2335

2336
2337
2338
2339
2340
2341
2342
....
2406
2407
2408
2409
2410
2411
2412

2413
2414
2415

2416
2417
2418
2419
2420
2421
2422
....
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
....
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
....
3800
3801
3802
3803
3804
3805
3806
3807


3808
3809
3810
3811
3812
3813
3814
....
3829
3830
3831
3832
3833
3834
3835
3836


3837
3838
3839
3840
3841
3842
3843
....
3967
3968
3969
3970
3971
3972
3973

3974
3975
3976
3977
3978
3979
3980
....
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
....
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
....
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
** 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.491 2008/09/17 20:06:26 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
    pPager->pInJournal = 0;
    sqlite3BitvecDestroy(pPager->pAlwaysRollback);
    pPager->pAlwaysRollback = 0;
    sqlite3PcacheCleanAll(pPager->pPCache);
#ifdef SQLITE_CHECK_PAGES
    sqlite3PcacheIterate(pPager->pPCache, pager_set_pagehash);
#endif
    sqlite3PcacheClearFlags(pPager->pPCache,
       PGHDR_IN_JOURNAL | PGHDR_NEED_SYNC
    );
    pPager->dirtyCache = 0;
    pPager->nRec = 0;
  }else{
    assert( pPager->pInJournal==0 );
  }

................................................................................
**              point of causing damage to the database during rollback.
**
** Numeric values associated with these states are OFF==1, NORMAL=2,
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){
  pPager->noSync =  level==1 || pPager->tempFile || MEMDB;
  pPager->fullSync = level==3 && !pPager->tempFile;
  pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL);
  if( pPager->noSync ) pPager->needSync = 0;
}
#endif

/*
................................................................................
    if( zPathname==0 ){
      return SQLITE_NOMEM;
    }
#ifndef SQLITE_OMIT_MEMORYDB
    if( strcmp(zFilename,":memory:")==0 ){
      memDb = 1;
      zPathname[0] = 0;
      useJournal = 0;
    }else
#endif
    {
      rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname);
    }
    if( rc!=SQLITE_OK ){
      sqlite3_free(zPathname);
................................................................................
    memcpy(pPager->zJournal, pPager->zFilename, nPathname);
    memcpy(&pPager->zJournal[nPathname], "-journal", 9);
  }else{
    pPager->zJournal = 0;
  }

  /* pPager->journalOpen = 0; */
  pPager->useJournal = useJournal;
  pPager->noReadlock = noReadlock && readOnly;
  /* pPager->stmtOpen = 0; */
  /* pPager->stmtInUse = 0; */
  /* pPager->nRef = 0; */
  pPager->dbSize = memDb-1;
  pPager->pageSize = szPageDflt;
  /* pPager->stmtSize = 0; */
................................................................................
      }
      pPager->journalStarted = 1;
    }
    pPager->needSync = 0;

    /* Erase the needSync flag from every page.
    */
    sqlite3PcacheClearFlags(pPager->pPCache, PGHDR_NEED_SYNC);

  }

#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{
    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_NEED_SYNC);

  }
#endif

  return rc;
}

/*
................................................................................
      PAGERTRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
    }
#endif
    if( rc ) return rc;
#ifdef SQLITE_CHECK_PAGES
    pList->pageHash = pager_pagehash(pList);
#endif

    pList = pList->pDirty;
  }


  return SQLITE_OK;
}

/*
** This function is called by the pcache layer when it has reached some
** soft memory limit. The argument is a pointer to a purgeable Pager 
** object. This function attempts to make a single dirty page that has no
................................................................................
    /* The pager cache has created a new page. Its content needs to 
    ** be initialized.
    */
    int nMax;
    PAGER_INCR(pPager->nMiss);
    pPg->pPager = pPager;
    if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
      assert( !MEMDB );
      pPg->flags |= PGHDR_IN_JOURNAL;
    }
    memset(pPg->pExtra, 0, pPager->nExtra);

    rc = sqlite3PagerPagecount(pPager, &nMax);
    if( rc!=SQLITE_OK ){
      sqlite3PagerUnref(pPg);
................................................................................
    /* If the PgHdr.needSync flag is set for any of the nPage pages 
    ** 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( 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);
    }
................................................................................
    assert( pPager->dirtyCache==0 || pPager->journalOpen==0 );
    return SQLITE_OK;
  }
  PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
  if( MEMDB ){
    sqlite3PcacheCommit(pPager->pPCache, 0);
    sqlite3PcacheCleanAll(pPager->pPCache);
    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);


    pPager->state = PAGER_SHARED;
  }else{
    assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
    rc = pager_end_transaction(pPager, pPager->setMaster);
    rc = pager_error(pPager, rc);
  }
  return rc;
................................................................................
int sqlite3PagerRollback(Pager *pPager){
  int rc = SQLITE_OK;
  PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
  if( MEMDB ){
    sqlite3PcacheRollback(pPager->pPCache, 1);
    sqlite3PcacheRollback(pPager->pPCache, 0);
    sqlite3PcacheCleanAll(pPager->pPCache);
    sqlite3PcacheAssertFlags(pPager->pPCache, 0, PGHDR_IN_JOURNAL);


    pPager->dbSize = pPager->origDbSize;
    pager_truncate_cache(pPager);
    pPager->stmtInUse = 0;
    pPager->state = PAGER_SHARED;
  }else if( !pPager->dirtyCache || !pPager->journalOpen ){
    rc = pager_end_transaction(pPager, pPager->setMaster);
  }else if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
................................................................................
/*
** Commit a statement.
*/
int sqlite3PagerStmtCommit(Pager *pPager){
  if( pPager->stmtInUse ){
    PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
    if( !MEMDB ){

      sqlite3BitvecDestroy(pPager->pInStmt);
      pPager->pInStmt = 0;
    }else{
      sqlite3PcacheCommit(pPager->pPCache, 1);
    }
    pPager->stmtNRec = 0;
    pPager->stmtInUse = 0;
................................................................................

#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page pPg to location pgno in the file.
**
** There must be no references to the page previously located at
** pgno (which we call pPgOld) though that page is allowed to be
** in cache.  If the page previously located at pgno is not already
** in the rollback journal, it is not put there by by this routine.
**
** References to the page pPg remain valid. Updating any
** meta-data associated with pPg (i.e. data stored in the nExtra bytes
** allocated along with the page) is the responsibility of the caller.
**
** A transaction must be active when this routine is called. It used to be
................................................................................
  pPg->flags &= ~(PGHDR_NEED_SYNC|PGHDR_IN_JOURNAL);
  pPgOld = pager_lookup(pPager, pgno);
  assert( !pPgOld || pPgOld->nRef==1 );
  if( pPgOld ){
    pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
  }
  if( sqlite3BitvecTest(pPager->pInJournal, pgno) ){
    assert( !MEMDB );
    pPg->flags |= PGHDR_IN_JOURNAL;
  }

  sqlite3PcacheMove(pPg, pgno);
  if( pPgOld ){
    sqlite3PcacheMove(pPgOld, 0);
    sqlite3PcacheRelease(pPgOld);
................................................................................
    if( rc!=SQLITE_OK ){
      if( pPager->pInJournal && (int)needSyncPgno<=pPager->origDbSize ){
        sqlite3BitvecClear(pPager->pInJournal, needSyncPgno);
      }
      return rc;
    }
    pPager->needSync = 1;
    assert( pPager->noSync==0 && !MEMDB );
    pPgHdr->flags |= PGHDR_NEED_SYNC;
    pPgHdr->flags |= PGHDR_IN_JOURNAL;
    makeDirty(pPgHdr);
    sqlite3PagerUnref(pPgHdr);
  }

  return SQLITE_OK;

Changes to src/pcache.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885

886
887
888
889
890
891
892
....
1000
1001
1002
1003
1004
1005
1006

1007
1008
1009
1010
1011
1012

1013
1014
1015
1016
1017
1018
1019
1020
1021
1022

1023
1024
1025
1026
1027
1028
1029
1030

1031
1032
1033
1034

1035
1036
1037
1038
1039
1040
1041
....
1042
1043
1044
1045
1046
1047
1048

1049
1050
1051
1052
1053
1054
1055
....
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190

1191
1192

1193
1194
1195

1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.28 2008/09/17 11:02:57 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
**
** A cache may only be deleted by its owner and while holding the
................................................................................
*/
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
  assert( p->nRef>0 );
  pcacheEnterMutex();
  pcacheRemoveFromHash(p);
  p->pgno = newPgno;
  if( newPgno==0 ){
    p->flags |= PGHDR_REUSE_UNLIKELY;
    pcacheFree(p->apSave[0]);
    pcacheFree(p->apSave[1]);
    p->apSave[0] = 0;
    p->apSave[1] = 0;
    if( (p->flags & PGHDR_DIRTY) ){
      pcacheMakeClean(p);
    }

  }
  pcacheAddToHash(p);
  pcacheExitMutex();
}

/*
** Remove all content from a page cache
................................................................................
}

/*
** Commit a change previously preserved.
*/
void sqlite3PcacheCommit(PCache *pCache, int idJournal){
  PgHdr *p;

  pcacheEnterMutex();     /* Mutex is required to call pcacheFree() */
  for(p=pCache->pDirty; p; p=p->pNext){
    if( p->apSave[idJournal] ){
      pcacheFree(p->apSave[idJournal]);
      p->apSave[idJournal] = 0;
    }

  }
  pcacheExitMutex();
}

/*
** Rollback a change previously preserved.
*/
void sqlite3PcacheRollback(PCache *pCache, int idJournal){
  PgHdr *p;
  int sz;

  pcacheEnterMutex();     /* Mutex is required to call pcacheFree() */
  sz = pCache->szPage;
  for(p=pCache->pDirty; p; p=p->pNext){
    if( p->apSave[idJournal] ){
      memcpy(p->pData, p->apSave[idJournal], sz);
      pcacheFree(p->apSave[idJournal]);
      p->apSave[idJournal] = 0;
    }

  }
  pcacheExitMutex();
}


/* 
** Assert flags settings on all pages.  Debugging only.
*/
void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
  PgHdr *p;
  for(p=pCache->pDirty; p; p=p->pNext){
    assert( (p->flags&trueMask)==trueMask );
................................................................................
    assert( (p->flags&falseMask)==0 );
  }
  for(p=pCache->pClean; p; p=p->pNext){
    assert( (p->flags&trueMask)==trueMask );
    assert( (p->flags&falseMask)==0 );
  }
}


/* 
** Discard the contents of the cache.
*/
int sqlite3PcacheClear(PCache *pCache){
  assert(pCache->nRef==0);
  pcacheEnterMutex();
................................................................................
  }
}
#endif

/* 
** Set flags on all pages in the page cache 
*/
void sqlite3PcacheSetFlags(PCache *pCache, int andMask, int orMask){
  PgHdr *p;

  assert( (orMask&PGHDR_NEED_SYNC)==0 );

  /* Obtain the global mutex before modifying any PgHdr.flags variables 
  ** or traversing the LRU list.
  */ 
  pcacheEnterMutex();


  for(p=pCache->pDirty; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;

  }
  for(p=pCache->pClean; p; p=p->pNext){
    p->flags = (p->flags&andMask)|orMask;

  }

  if( 0==(andMask&PGHDR_NEED_SYNC) ){
    pCache->pSynced = pCache->pDirtyTail;
    assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 );
  }

  pcacheExitMutex();
}








|







 







<







>







 







>






>










>








>




>







 







>







 







|


<
<





>

<
>


<
>


|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
871
872
873
874
875
876
877

878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
....
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
....
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
....
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189


1190
1191
1192
1193
1194
1195
1196

1197
1198
1199

1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.29 2008/09/17 20:06:26 drh Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
**
** A cache may only be deleted by its owner and while holding the
................................................................................
*/
void sqlite3PcacheMove(PgHdr *p, Pgno newPgno){
  assert( p->nRef>0 );
  pcacheEnterMutex();
  pcacheRemoveFromHash(p);
  p->pgno = newPgno;
  if( newPgno==0 ){

    pcacheFree(p->apSave[0]);
    pcacheFree(p->apSave[1]);
    p->apSave[0] = 0;
    p->apSave[1] = 0;
    if( (p->flags & PGHDR_DIRTY) ){
      pcacheMakeClean(p);
    }
    p->flags = PGHDR_REUSE_UNLIKELY;
  }
  pcacheAddToHash(p);
  pcacheExitMutex();
}

/*
** Remove all content from a page cache
................................................................................
}

/*
** Commit a change previously preserved.
*/
void sqlite3PcacheCommit(PCache *pCache, int idJournal){
  PgHdr *p;
  int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff;
  pcacheEnterMutex();     /* Mutex is required to call pcacheFree() */
  for(p=pCache->pDirty; p; p=p->pNext){
    if( p->apSave[idJournal] ){
      pcacheFree(p->apSave[idJournal]);
      p->apSave[idJournal] = 0;
    }
    p->flags &= mask;
  }
  pcacheExitMutex();
}

/*
** Rollback a change previously preserved.
*/
void sqlite3PcacheRollback(PCache *pCache, int idJournal){
  PgHdr *p;
  int sz;
  int mask = idJournal==0 ? ~PGHDR_IN_JOURNAL : 0xffffff;
  pcacheEnterMutex();     /* Mutex is required to call pcacheFree() */
  sz = pCache->szPage;
  for(p=pCache->pDirty; p; p=p->pNext){
    if( p->apSave[idJournal] ){
      memcpy(p->pData, p->apSave[idJournal], sz);
      pcacheFree(p->apSave[idJournal]);
      p->apSave[idJournal] = 0;
    }
    p->flags &= mask;
  }
  pcacheExitMutex();
}

#ifndef NDEBUG
/* 
** Assert flags settings on all pages.  Debugging only.
*/
void sqlite3PcacheAssertFlags(PCache *pCache, int trueMask, int falseMask){
  PgHdr *p;
  for(p=pCache->pDirty; p; p=p->pNext){
    assert( (p->flags&trueMask)==trueMask );
................................................................................
    assert( (p->flags&falseMask)==0 );
  }
  for(p=pCache->pClean; p; p=p->pNext){
    assert( (p->flags&trueMask)==trueMask );
    assert( (p->flags&falseMask)==0 );
  }
}
#endif

/* 
** Discard the contents of the cache.
*/
int sqlite3PcacheClear(PCache *pCache){
  assert(pCache->nRef==0);
  pcacheEnterMutex();
................................................................................
  }
}
#endif

/* 
** Set flags on all pages in the page cache 
*/
void sqlite3PcacheClearFlags(PCache *pCache, int mask){
  PgHdr *p;



  /* Obtain the global mutex before modifying any PgHdr.flags variables 
  ** or traversing the LRU list.
  */ 
  pcacheEnterMutex();

  mask = ~mask;
  for(p=pCache->pDirty; p; p=p->pNext){

    p->flags &= mask;
  }
  for(p=pCache->pClean; p; p=p->pNext){

    p->flags &= mask;
  }

  if( 0==(mask&PGHDR_NEED_SYNC) ){
    pCache->pSynced = pCache->pDirtyTail;
    assert( !pCache->pSynced || (pCache->pSynced->flags&PGHDR_NEED_SYNC)==0 );
  }

  pcacheExitMutex();
}

Changes to src/pcache.h.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64
65
66
67
68
69
...
118
119
120
121
122
123
124
125
126
127
128

129



130
131
132
133
134
135
136
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem. 
**
** @(#) $Id: pcache.h,v 1.9 2008/08/29 09:10:03 danielk1977 Exp $
*/

#ifndef _PCACHE_H_

typedef struct PgHdr PgHdr;
typedef struct PCache PCache;

................................................................................
  PgHdr *pNextHash, *pPrevHash;  /* Hash collision chain for PgHdr.pgno */
  PgHdr *pNext, *pPrev;          /* List of clean or dirty pages */
  PgHdr *pNextLru, *pPrevLru;    /* Part of global LRU list */
};

/* Bit values for PgHdr.flags */
#define PGHDR_IN_JOURNAL        0x001  /* Page is in rollback journal */
#define PGHDR_IN_STMTJRNL       0x002  /* Page is in the statement journal */
#define PGHDR_DIRTY             0x004  /* Page has changed */
#define PGHDR_NEED_SYNC         0x008  /* Peed to fsync this page */

#define PGHDR_NEED_READ         0x020  /* Content is unread */
#define PGHDR_IS_INIT           0x040  /* pData is initialized */
#define PGHDR_REUSE_UNLIKELY    0x080  /* Hint: Reuse is unlikely */
#define PGHDR_DONT_WRITE        0x100  /* Do not write content to disk */

/* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void);
void sqlite3PcacheShutdown(void);

/* Page cache buffer management:
** These routines implement SQLITE_CONFIG_PAGECACHE.
................................................................................

/* Get a list of all dirty pages in the cache, sorted by page number */
PgHdr *sqlite3PcacheDirtyList(PCache*);

/* Reset and close the cache object */
void sqlite3PcacheClose(PCache*);

/* Set flags on all pages in the page cache */
void sqlite3PcacheSetFlags(PCache*, int andMask, int orMask);

/* Assert flags settings on all pages.  Debugging only */

void sqlite3PcacheAssertFlags(PCache*, int trueMask, int falseMask);




/* Return true if the number of dirty pages is 0 or 1 */
int sqlite3PcacheZeroOrOneDirtyPages(PCache*);

/* Discard the contents of the cache */
int sqlite3PcacheClear(PCache*);








|







 







<
|
|
>
|
<
|
|







 







|
|


>
|
>
>
>







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
49
50
51
52
53
54
55

56
57
58
59

60
61
62
63
64
65
66
67
68
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the sqlite page cache
** subsystem. 
**
** @(#) $Id: pcache.h,v 1.10 2008/09/17 20:06:26 drh Exp $
*/

#ifndef _PCACHE_H_

typedef struct PgHdr PgHdr;
typedef struct PCache PCache;

................................................................................
  PgHdr *pNextHash, *pPrevHash;  /* Hash collision chain for PgHdr.pgno */
  PgHdr *pNext, *pPrev;          /* List of clean or dirty pages */
  PgHdr *pNextLru, *pPrevLru;    /* Part of global LRU list */
};

/* Bit values for PgHdr.flags */
#define PGHDR_IN_JOURNAL        0x001  /* Page is in rollback journal */

#define PGHDR_DIRTY             0x002  /* Page has changed */
#define PGHDR_NEED_SYNC         0x004  /* Fsync the rollback journal before
                                       ** writing this page to the database */
#define PGHDR_NEED_READ         0x008  /* Content is unread */

#define PGHDR_REUSE_UNLIKELY    0x010  /* A hint that reuse is unlikely */
#define PGHDR_DONT_WRITE        0x020  /* Do not write content to disk */

/* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void);
void sqlite3PcacheShutdown(void);

/* Page cache buffer management:
** These routines implement SQLITE_CONFIG_PAGECACHE.
................................................................................

/* Get a list of all dirty pages in the cache, sorted by page number */
PgHdr *sqlite3PcacheDirtyList(PCache*);

/* Reset and close the cache object */
void sqlite3PcacheClose(PCache*);

/* Clear flags from pages of the page cache */
void sqlite3PcacheClearFlags(PCache*, int mask);

/* Assert flags settings on all pages.  Debugging only */
#ifndef NDEBUG
  void sqlite3PcacheAssertFlags(PCache*, int trueMask, int falseMask);
#else
# define sqlite3PcacheAssertFlags(A,B,C)
#endif

/* Return true if the number of dirty pages is 0 or 1 */
int sqlite3PcacheZeroOrOneDirtyPages(PCache*);

/* Discard the contents of the cache */
int sqlite3PcacheClear(PCache*);