/ Check-in [701302b4]
Login

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

Overview
Comment:Consolidate two blocks of similar code in btreeFixUnlocked().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | begin-concurrent
Files: files | file ages | folders
SHA1: 701302b4bd62ca7aefe643eac096a0ee672a62fa
User & Date: dan 2015-08-24 10:05:03
Wiki:begin-concurrent
Context
2015-08-24
16:00
Fix compilation without SQLITE_ENABLE_UNLOCKED. Also other code organization issues. check-in: 04113557 user: dan tags: begin-concurrent
10:05
Consolidate two blocks of similar code in btreeFixUnlocked(). check-in: 701302b4 user: dan tags: begin-concurrent
06:44
Merge trunk changes with this branch. check-in: 876810c2 user: dan tags: begin-concurrent
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

3843
3844
3845
3846
3847
3848
3849



































































3850
3851
3852
3853
3854
3855
3856
....
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
....
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915

3916

3917
3918
3919
3920
3921

3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947

3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
}

#else /* ifndef SQLITE_OMIT_AUTOVACUUM */
# define setChildPtrmaps(x) SQLITE_OK
#endif

#ifdef SQLITE_ENABLE_UNLOCKED



































































/*
** The b-tree handle passed as the only argument is about to commit an
** UNLOCKED transaction. At this point it is guaranteed that this is 
** possible - the wal WRITER lock is held and it is known that there are 
** no conflicts with committed transactions.
*/
static int btreeFixUnlocked(Btree *p){
................................................................................
  assert( sqlite3PagerIsUnlocked(pPager) );
  assert( pBt->pMap );
  rc = sqlite3PagerUpgradeSnapshot(pPager, pPage1->pDbPage);
  assert( p1==pPage1->aData );

  if( rc==SQLITE_OK ){
    Pgno nHPage = get4byte(&p1[28]);
    Pgno nFinal = nHPage;         /* Size of db after transaction merge */

    if( sqlite3PagerIswriteable(pPage1->pDbPage) ){
      Pgno iHTrunk = get4byte(&p1[32]);
      u32 nHFree = get4byte(&p1[36]);

      /* Attach the head database free list to the end of the current
      ** transactions free-list (if any).  */
................................................................................
        ** not have shrunk since the transaction was opened. Therefore nHPage
        ** should be set to (pMap->iFirst-1) or greater. */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        /* The current transaction allocated pages pMap->iFirst through
        ** nPage (inclusive) at the end of the database file. Meanwhile,
        ** other transactions have allocated (iFirst..nHPage). So move
        ** pages (iFirst..MIN(nPage,nHPage)) to (MAX(nPage,nHPage)+1).
        */
        Pgno iLast = MIN(nPage, nHPage);    /* Last page to move */
        Pgno iPg;
        Pgno nCurrent;                      /* Current size of db */
        nCurrent = MAX(nPage, nHPage);



        for(iPg=pMap->iFirst; iPg<=iLast && rc==SQLITE_OK; iPg++){
          MemPage *pPg = 0;
          Pgno iNew;              /* New page number for pPg */
          PtrmapEntry *pEntry;    /* Pointer map entry for page iPg */


          if( iPg==PENDING_BYTE_PAGE(pBt) ) continue;
          pEntry = &pMap->aPtr[iPg - pMap->iFirst];
          if( pEntry->eType==PTRMAP_FREEPAGE ){
            MemPage *pFree = 0;
            Pgno dummy;
            rc = allocateBtreePage(pBt, &pFree, &dummy, iPg, BTALLOC_EXACT);
            releasePage(pFree);
            assert( rc!=SQLITE_OK || dummy==iPg );
          }else{
            btreeGetPage(pBt, iPg, &pPg, 0);
            assert( sqlite3PagerIswriteable(pPg->pDbPage) );
            assert( sqlite3PagerPageRefcount(pPg->pDbPage)==1 );
            iNew = ++nCurrent;
            if( iNew==PENDING_BYTE_PAGE(pBt) ) iNew = ++nCurrent;
            rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent, iNew, 1);
            releasePageNotNull(pPg);
          }
        }
        sqlite3PagerSetDbsize(pPager, nCurrent);
        assert( nCurrent!=PENDING_BYTE_PAGE(pBt) );

        nFree = get4byte(&p1[36]);
        nFinal = MAX(nCurrent-nFree, nHPage);
        if( nCurrent>PENDING_BYTE_PAGE(pBt) && nFinal<=PENDING_BYTE_PAGE(pBt) ){
          nFinal--;
        }


        for(iPg=nFinal+1; rc==SQLITE_OK && iPg<=nCurrent; iPg++){
          Pgno iNew;              /* New page number for pPg */
          MemPage *pFree;
          PtrmapEntry *pEntry;    /* Pointer map entry for page iPg */

          if( iPg==PENDING_BYTE_PAGE(pBt) ) continue;
          pEntry = &pMap->aPtr[iPg - pMap->iFirst];
          if( pEntry->eType==PTRMAP_FREEPAGE ){
            rc = allocateBtreePage(pBt, &pFree, &iNew, iPg, BTALLOC_EXACT);
            releasePage(pFree);
          }else{
            rc = allocateBtreePage(pBt, &pFree, &iNew, nFinal, BTALLOC_LE);
            assert( rc!=SQLITE_OK || iNew<=nFinal );
            releasePage(pFree);
            if( rc==SQLITE_OK ){
              MemPage *pPg = 0;
              btreeGetPage(pBt, iPg, &pPg, 0);
              rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent,iNew,1);
              releasePage(pPg);
            }
          }
        }
        put4byte(&p1[28], nFinal);
      }
    }
    sqlite3PagerSetDbsize(pPager, nFinal);
  }

  return rc;
}
#endif

/*







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|
<

<


>

>
|
|
|
|
<
>
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
|
|
|
|
>
|
<
<
<
<

<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|


|







3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
....
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
....
3970
3971
3972
3973
3974
3975
3976
3977

3978

3979
3980
3981
3982
3983
3984
3985
3986
3987

3988
3989

















3990


3991
3992
3993
3994
3995
3996
3997




3998

















3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
}

#else /* ifndef SQLITE_OMIT_AUTOVACUUM */
# define setChildPtrmaps(x) SQLITE_OK
#endif

#ifdef SQLITE_ENABLE_UNLOCKED
/*
** This function is called as part of merging an UNLOCKED transaction with
** the snapshot at the head of the wal file. It relocates all pages in the
** range iFirst..iLast, inclusive. It is assumed that the BtreePtrmap 
** structure at BtShared.pMap contains the location of the pointers to each
** page in the range.
**
** If pnCurrent is NULL, then all pages in the range are moved to currently
** free locations (i.e. free-list entries) within the database file before page
** iFirst.
**
** Or, if pnCurrent is not NULL, then it points to a value containing the
** current size of the database file in pages. In this case, all pages are
** relocated to the end of the database file - page iFirst is relocated to
** page (*pnCurrent+1), page iFirst+1 to page (*pnCurrent+2), and so on.
** Value *pnCurrent is set to the new size of the database before this 
** function returns.
**
** If no error occurs, SQLITE_OK is returned. Otherwise, an SQLite error code.
*/
static int btreeRelocateRange(
  BtShared *pBt,                  /* B-tree handle */
  Pgno iFirst,                    /* First page to relocate */
  Pgno iLast,                     /* Last page to relocate */
  Pgno *pnCurrent                 /* If not NULL, IN/OUT: Database size */
){
  int rc = SQLITE_OK;
  BtreePtrmap *pMap = pBt->pMap;
  Pgno iPg;

  for(iPg=iFirst; iPg<=iLast && rc==SQLITE_OK; iPg++){
    MemPage *pFree = 0;     /* Page allocated from free-list */
    MemPage *pPg = 0;
    Pgno iNew;              /* New page number for pPg */
    PtrmapEntry *pEntry;    /* Pointer map entry for page iPg */

    if( iPg==PENDING_BYTE_PAGE(pBt) ) continue;
    pEntry = &pMap->aPtr[iPg - pMap->iFirst];

    if( pEntry->eType==PTRMAP_FREEPAGE ){
      Pgno dummy;
      rc = allocateBtreePage(pBt, &pFree, &dummy, iPg, BTALLOC_EXACT);
      releasePage(pFree);
      assert( rc!=SQLITE_OK || dummy==iPg );
    }else if( pnCurrent ){
      btreeGetPage(pBt, iPg, &pPg, 0);
      assert( sqlite3PagerIswriteable(pPg->pDbPage) );
      assert( sqlite3PagerPageRefcount(pPg->pDbPage)==1 );
      iNew = ++(*pnCurrent);
      if( iNew==PENDING_BYTE_PAGE(pBt) ) iNew = ++(*pnCurrent);
      rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent, iNew, 1);
      releasePageNotNull(pPg);
    }else{
      rc = allocateBtreePage(pBt, &pFree, &iNew, iFirst-1, BTALLOC_LE);
      assert( rc!=SQLITE_OK || iNew<iFirst );
      releasePage(pFree);
      if( rc==SQLITE_OK ){
        MemPage *pPg = 0;
        btreeGetPage(pBt, iPg, &pPg, 0);
        rc = relocatePage(pBt, pPg, pEntry->eType, pEntry->parent,iNew,1);
        releasePage(pPg);
      }
    }
  }
  return rc;
}

/*
** The b-tree handle passed as the only argument is about to commit an
** UNLOCKED transaction. At this point it is guaranteed that this is 
** possible - the wal WRITER lock is held and it is known that there are 
** no conflicts with committed transactions.
*/
static int btreeFixUnlocked(Btree *p){
................................................................................
  assert( sqlite3PagerIsUnlocked(pPager) );
  assert( pBt->pMap );
  rc = sqlite3PagerUpgradeSnapshot(pPager, pPage1->pDbPage);
  assert( p1==pPage1->aData );

  if( rc==SQLITE_OK ){
    Pgno nHPage = get4byte(&p1[28]);
    Pgno nFin = nHPage;         /* Size of db after transaction merge */

    if( sqlite3PagerIswriteable(pPage1->pDbPage) ){
      Pgno iHTrunk = get4byte(&p1[32]);
      u32 nHFree = get4byte(&p1[36]);

      /* Attach the head database free list to the end of the current
      ** transactions free-list (if any).  */
................................................................................
        ** not have shrunk since the transaction was opened. Therefore nHPage
        ** should be set to (pMap->iFirst-1) or greater. */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        /* The current transaction allocated pages pMap->iFirst through
        ** nPage (inclusive) at the end of the database file. Meanwhile,
        ** other transactions have allocated (iFirst..nHPage). So move
        ** pages (iFirst..MIN(nPage,nHPage)) to (MAX(nPage,nHPage)+1).  */

        Pgno iLast = MIN(nPage, nHPage);    /* Last page to move */

        Pgno nCurrent;                      /* Current size of db */
        nCurrent = MAX(nPage, nHPage);
        rc = btreeRelocateRange(pBt, pMap->iFirst, iLast, &nCurrent);

        /* There are now no collisions with the snapshot at the head of the
        ** database file. So at this point it would be possible to write
        ** the transaction out to disk. Before doing so though, attempt to
        ** relocate some of the new pages to free locations within the body
        ** of the database file (i.e. free-list entries). */

        if( rc==SQLITE_OK ){
          assert( nCurrent!=PENDING_BYTE_PAGE(pBt) );

















          sqlite3PagerSetDbsize(pBt->pPager, nCurrent);


          nFree = get4byte(&p1[36]);
          nFin = MAX(nCurrent-nFree, nHPage);
          if( nCurrent>PENDING_BYTE_PAGE(pBt) && nFin<=PENDING_BYTE_PAGE(pBt) ){
            nFin--;
          }
          rc = btreeRelocateRange(pBt, nFin+1, nCurrent, 0);
        }






















        put4byte(&p1[28], nFin);
      }
    }
    sqlite3PagerSetDbsize(pPager, nFin);
  }

  return rc;
}
#endif

/*

Changes to test/unlocked3.test.

80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97


98
99
100
101
102
103
104
}


set DBLIST {db1 db2 db3 db4} 

create_schema
foreach {tn oplist} {
  1 {1i   2i   3i   4i} 
  2 {1iii 2iii 3iii 4iii}
  3 {1d   2d   3d   4d} 
  . -----------------------
  4 {1i}
  5 {1d 2i}
  . -----------------------
  6 {1iii 2iii 3iii 4iii}
  7 {1di  2id  3iii 4ddd}
  8 {1iii 2iii 3iii 4iii}
  9 {1D  2II}


} {
  if {[string range $oplist 0 0]=="-"} {
    reset_db
    create_schema
    continue
  }
  foreach db $DBLIST { sqlite3 $db test.db }







|
|
|
|
|
|
|
|
|
|
|
>
>







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
}


set DBLIST {db1 db2 db3 db4} 

create_schema
foreach {tn oplist} {
  1  {1i   2i   3i   4i} 
  2  {1iii 2iii 3iii 4iii}
  3  {1d   2d   3d   4d} 
  .  -----------------------
  4  {1i}
  5  {1d 2i}
  .  -----------------------
  6  {1iii 2iii 3iii 4iii}
  7  {1di  2id  3iii 4ddd}
  8  {1iii 2iii 3iii 4iii}
  9  {1D  2II}
  10 {1I  2D  3I  4D}
  11 {1III 3dddddd 4III}
} {
  if {[string range $oplist 0 0]=="-"} {
    reset_db
    create_schema
    continue
  }
  foreach db $DBLIST { sqlite3 $db test.db }