/ Check-in [7c22aa3f]
Login

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

Overview
Comment:Fix a bug in the rollback logic for the new journal format. (CVS 864)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7c22aa3f817e737cfd943d903856756468e8678b
User & Date: drh 2003-02-13 01:58:21
Context
2003-02-13
02:54
Update the documentation for the new journal format to be introduced in version 2.8.0. (CVS 865) check-in: e05a7a55 user: drh tags: trunk
01:58
Fix a bug in the rollback logic for the new journal format. (CVS 864) check-in: 7c22aa3f user: drh tags: trunk
2003-02-12
14:09
Added the new FULL option to the SYNCHRONOUS pragma. Still need to test it. (CVS 1728) check-in: 8968bc06 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
...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
...
630
631
632
633
634
635
636
637

638
639
640
641
642
643
644
645
646
647
648
649
650

651
652
653
654
655
656
657
...
659
660
661
662
663
664
665
666

667
668
669
670
671
672
673
....
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
....
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
....
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
** 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.75 2003/02/12 14:09:44 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
  char *zJournal;             /* Name of the journal file */
  OsFile fd, jfd;             /* File descriptors for database and journal */
  OsFile cpfd;                /* File descriptor for the checkpoint journal */
  int dbSize;                 /* Number of pages in the file */
  int origDbSize;             /* dbSize before the current change */
  int ckptSize;               /* Size of database (in pages) at ckpt_begin() */
  off_t ckptJSize;            /* Size of journal at ckpt_begin() */
#ifndef NDEBUG
  off_t syncJSize;            /* Size of journal at last fsync() call */
#endif
  int nRec;                   /* Number of pages written to the journal */
  u32 cksumInit;              /* Quasi-random value added to every checksum */
  int ckptNRec;               /* Number of records in the checkpoint journal */
  int nExtra;                 /* Add this many bytes to each in-memory page */
  void (*xDestructor)(void*); /* Call this routine when freeing pages */
  int nPage;                  /* Total number of in-memory pages */
  int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
................................................................................
      if( rc==SQLITE_DONE ){
        rc = SQLITE_OK;
      }
      break;
    }
  }



end_playback:
#if !defined(NDEBUG) && defined(SQLITE_TEST)
  /* For pages that were never written into the journal, restore the
  ** memory copy from the original database file.
  **
  ** This is code is used during testing only.  It is necessary to
  ** compensate for the sqliteOsTruncate() call inside 
  ** sqlitepager_rollback().
  */
  if( rc==SQLITE_OK ){
    PgHdr *pPg;
    for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
      char zBuf[SQLITE_PAGE_SIZE];

      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);
        if( rc ) break;
      }else{
        memset(zBuf, 0, 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;
    }
  }
#endif

  if( rc!=SQLITE_OK ){
    pager_unwritelock(pPager);
    pPager->errMask |= PAGER_ERR_CORRUPT;
    rc = SQLITE_CORRUPT;
  }else{
    rc = pager_unwritelock(pPager);
  }
................................................................................
  */
  if( pPager->needSync ){
    if( !pPager->tempFile ){
      assert( pPager->journalOpen );
      assert( !pPager->noSync );
#ifndef NDEBUG
      {
        off_t hdrSz, pgSz;
        hdrSz = JOURNAL_HDR_SZ(journal_format);
        pgSz = JOURNAL_PG_SZ(journal_format);
        rc = sqliteOsFileSize(&pPager->jfd, &pPager->syncJSize);
        if( rc!=0 ) return rc;
        assert( pPager->nRec*pgSz+hdrSz==pPager->syncJSize );
      }
#endif
      if( journal_format>=3 ){
        off_t szJ;
        if( pPager->fullSync ){
          TRACE1("SYNC\n");
          rc = sqliteOsSync(&pPager->jfd);
................................................................................
  }
  if( rc!=SQLITE_OK ){
    rc = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }
#ifndef NDEBUG
  pPager->syncJSize = 0;
#endif
  return rc;  
}

/*
** Acquire a write-lock on the database.  The lock is removed when
** the any of the following happen:
**
................................................................................
  TRACE1("ROLLBACK\n");
  if( !pPager->dirtyFile || !pPager->journalOpen ){
    rc = pager_unwritelock(pPager);
    pPager->dbSize = -1;
    return rc;
  }

#if defined(SQLITE_TEST) && !defined(NDEBUG)
  /* Truncate the journal to the size it was at the conclusion of the
  ** last sqliteOsSync() call.  This is really an error check.  If the
  ** rollback still works, it means that the rollback would have also
  ** worked if it had occurred after an OS crash or unexpected power
  ** loss.
  */
  if( !pPager->noSync ){
    int m = JOURNAL_HDR_SZ(journal_format);
    assert( !pPager->tempFile );
    if( pPager->syncJSize<m ){
      pPager->syncJSize = m;
    }
    TRACE2("TRUNCATE JOURNAL %lld\n", pPager->syncJSize);
    rc =  sqliteOsTruncate(&pPager->jfd, pPager->syncJSize);
    if( rc ) return rc;
    pPager->nRec = 0;
  }
#endif

  if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
    if( pPager->state>=SQLITE_WRITELOCK ){
      pager_playback(pPager);
    }
    return pager_errcode(pPager);
  }
  if( pPager->state!=SQLITE_WRITELOCK ){







|







 







<
<
<







 







<
>
|
<
<
|
<
<
<
<





>







 







|
>







 







|


|

|







 







<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
131
132
133
134
135
136
137



138
139
140
141
142
143
144
...
627
628
629
630
631
632
633

634
635


636




637
638
639
640
641
642
643
644
645
646
647
648
649
...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
....
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
....
1531
1532
1533
1534
1535
1536
1537



1538
1539
1540
1541
1542
1543
1544
....
1875
1876
1877
1878
1879
1880
1881




















1882
1883
1884
1885
1886
1887
1888
** 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.76 2003/02/13 01:58:21 drh Exp $
*/
#include "os.h"         /* Must be first to enable large file support */
#include "sqliteInt.h"
#include "pager.h"
#include <assert.h>
#include <string.h>

................................................................................
  char *zJournal;             /* Name of the journal file */
  OsFile fd, jfd;             /* File descriptors for database and journal */
  OsFile cpfd;                /* File descriptor for the checkpoint journal */
  int dbSize;                 /* Number of pages in the file */
  int origDbSize;             /* dbSize before the current change */
  int ckptSize;               /* Size of database (in pages) at ckpt_begin() */
  off_t ckptJSize;            /* Size of journal at ckpt_begin() */



  int nRec;                   /* Number of pages written to the journal */
  u32 cksumInit;              /* Quasi-random value added to every checksum */
  int ckptNRec;               /* Number of records in the checkpoint journal */
  int nExtra;                 /* Add this many bytes to each in-memory page */
  void (*xDestructor)(void*); /* Call this routine when freeing pages */
  int nPage;                  /* Total number of in-memory pages */
  int nRef;                   /* Number of in-memory pages with PgHdr.nRef>0 */
................................................................................
      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 the 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);
        if( rc ) break;
      }else{
        memset(zBuf, 0, 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);
  }
................................................................................
  */
  if( pPager->needSync ){
    if( !pPager->tempFile ){
      assert( pPager->journalOpen );
      assert( !pPager->noSync );
#ifndef NDEBUG
      {
        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 ){
        off_t szJ;
        if( pPager->fullSync ){
          TRACE1("SYNC\n");
          rc = sqliteOsSync(&pPager->jfd);
................................................................................
  }
  if( rc!=SQLITE_OK ){
    rc = pager_unwritelock(pPager);
    if( rc==SQLITE_OK ){
      rc = SQLITE_FULL;
    }
  }



  return rc;  
}

/*
** Acquire a write-lock on the database.  The lock is removed when
** the any of the following happen:
**
................................................................................
  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);
    }
    return pager_errcode(pPager);
  }
  if( pPager->state!=SQLITE_WRITELOCK ){