/ Check-in [12363184]
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:Further tests and changes related to switching between WAL and rollback modes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | wal
Files: files | file ages | folders
SHA1: 1236318477787a612f02cc98caf2931bd2e99d94
User & Date: dan 2010-04-22 06:27:05
Context
2010-04-22
19:14
Create a version of the log checksummer that works on big-endian platforms. Remove the 512KB size limit on the log-summary. check-in: 5d6d4423 user: dan tags: wal
06:27
Further tests and changes related to switching between WAL and rollback modes. check-in: 12363184 user: dan tags: wal
2010-04-21
18:37
Tests for (and changes to) the code to switch between WAL and rollback modes. check-in: 9f4f933f user: dan tags: wal
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
  */
  pBt->doNotUseWAL = (iVersion==1);

  rc = sqlite3BtreeBeginTrans(pBtree, 0);
  if( rc==SQLITE_OK ){
    u8 *aData = pBt->pPage1->aData;
    if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
      rc = sqlite3BtreeBeginTrans(pBtree, 1);
      if( rc==SQLITE_OK ){
        rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
        if( rc==SQLITE_OK ){
          aData[18] = (u8)iVersion;
          aData[19] = (u8)iVersion;
        }
      }
    }
  }

  pBt->doNotUseWAL = 0;
  return rc;
}







|













8000
8001
8002
8003
8004
8005
8006
8007
8008
8009
8010
8011
8012
8013
8014
8015
8016
8017
8018
8019
8020
  */
  pBt->doNotUseWAL = (iVersion==1);

  rc = sqlite3BtreeBeginTrans(pBtree, 0);
  if( rc==SQLITE_OK ){
    u8 *aData = pBt->pPage1->aData;
    if( aData[18]!=(u8)iVersion || aData[19]!=(u8)iVersion ){
      rc = sqlite3BtreeBeginTrans(pBtree, 2);
      if( rc==SQLITE_OK ){
        rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
        if( rc==SQLITE_OK ){
          aData[18] = (u8)iVersion;
          aData[19] = (u8)iVersion;
        }
      }
    }
  }

  pBt->doNotUseWAL = 0;
  return rc;
}

Changes to src/pager.c.

3728
3729
3730
3731
3732
3733
3734
3735


3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
....
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760








5761


5762





5763




5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
/*
** Check if the *-wal file that corresponds to the database opened by pPager
** exists. Assuming no error occurs, set *pExists to 1 if the file exists,
** or 0 otherwise and return SQLITE_OK. If an IO or OOM error occurs, return
** an SQLite error code.
**
** The caller must hold a SHARED lock on the database file to call this
** function.


*/
static int pagerHasWAL(Pager *pPager, int *pExists){
  int rc;                         /* Return code */

  /* Check that a SHARED lock is held on the database file. Because an
  ** EXCLUSIVE lock on the db file is required to delete a WAL, this
  ** ensures there is no race condition between the xAccess() below and
  ** an xDelete() being executed by some other connection.
  */
  assert( pPager->state>=PAGER_SHARED );

  if( !pPager->tempFile ){
    char *zLog = sqlite3_mprintf("%s-wal", pPager->zFilename);
    if( !zLog ){
      rc = SQLITE_NOMEM;
    }else{
      rc = sqlite3OsAccess(pPager->pVfs, zLog, SQLITE_ACCESS_EXISTS, pExists);
      sqlite3_free(zLog);
................................................................................
** Before closing the log file, this function attempts to take an 
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
int sqlite3PagerCloseLog(Pager *pPager){
  int rc = SQLITE_OK;
  if( pPager->pLog ){

    /* Try to obtain an EXCLUSIVE lock on the database file. */








    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);








    /* If the EXCLUSIVE lock was obtained, checkpoint and close the log. */




    if( rc==SQLITE_OK ){
      rc = sqlite3LogClose(pPager->pLog, pPager->fd,
        (pPager->noSync ? 0 : pPager->sync_flags), 
        (u8*)pPager->pTmpSpace
      );
      pPager->pLog = 0;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_DISKIO */







|
>
>




<
<
<
<
<
<
<







 







<

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












3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741







3742
3743
3744
3745
3746
3747
3748
....
5746
5747
5748
5749
5750
5751
5752

5753

5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
5785
5786
5787
/*
** Check if the *-wal file that corresponds to the database opened by pPager
** exists. Assuming no error occurs, set *pExists to 1 if the file exists,
** or 0 otherwise and return SQLITE_OK. If an IO or OOM error occurs, return
** an SQLite error code.
**
** The caller must hold a SHARED lock on the database file to call this
** function. Because an EXCLUSIVE lock on the db file is required to delete 
** a WAL, this ensures there is no race condition between the xAccess() 
** below and an xDelete() being executed by some other connection.
*/
static int pagerHasWAL(Pager *pPager, int *pExists){
  int rc;                         /* Return code */








  if( !pPager->tempFile ){
    char *zLog = sqlite3_mprintf("%s-wal", pPager->zFilename);
    if( !zLog ){
      rc = SQLITE_NOMEM;
    }else{
      rc = sqlite3OsAccess(pPager->pVfs, zLog, SQLITE_ACCESS_EXISTS, pExists);
      sqlite3_free(zLog);
................................................................................
** Before closing the log file, this function attempts to take an 
** EXCLUSIVE lock on the database file. If this cannot be obtained, an
** error (SQLITE_BUSY) is returned and the log connection is not closed.
** If successful, the EXCLUSIVE lock is not released before returning.
*/
int sqlite3PagerCloseLog(Pager *pPager){
  int rc = SQLITE_OK;



  assert( pPager->journalMode==PAGER_JOURNALMODE_WAL );

  /* If the log file is not already open, but does exist in the file-system,
  ** it may need to be checkpointed before the connection can switch to
  ** rollback mode. Open it now so this can happen.
  */
  if( !pPager->pLog ){
    int logexists = 0;
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = pagerHasWAL(pPager, &logexists);
    }
    if( rc==SQLITE_OK && logexists ){
      rc = sqlite3LogOpen(pPager->pVfs, pPager->zFilename, &pPager->pLog);
    }
  }
    
  /* Checkpoint and close the log. Because an EXCLUSIVE lock is held on
  ** the database file, the log and log-summary files will be deleted.
  */
  if( rc==SQLITE_OK && pPager->pLog ){
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_EXCLUSIVE);
    if( rc==SQLITE_OK ){
      rc = sqlite3LogClose(pPager->pLog, pPager->fd,
        (pPager->noSync ? 0 : pPager->sync_flags), 
        (u8*)pPager->pTmpSpace
      );
      pPager->pLog = 0;
    }
  }
  return rc;
}

#endif /* SQLITE_OMIT_DISKIO */

Changes to src/vdbe.c.

5240
5241
5242
5243
5244
5245
5246

5247
5248
5249

5250
5251
5252
5253
5254
5255
5256
5257
5258
        rc = SQLITE_ERROR;
        sqlite3SetString(&p->zErrMsg, db, 
            "cannot change %s wal mode from within a transaction",
            (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
        );
      }else{
  

        /* If leaving WAL mode, close the log file. If successful, the call to
        ** PagerCloseLog() checkpoints and deletes the write-ahead-log file.
        ** An EXCLUSIVE lock is still held on the database file after returning.

        */
        if( eOld==PAGER_JOURNALMODE_WAL ){
          rc = sqlite3PagerCloseLog(pPager);
          if( rc!=SQLITE_OK ) goto abort_due_to_error;
          sqlite3PagerJournalMode(pPager, eNew);
        }else{
          sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
        }
  







>
|
|
|
>
|
<







5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252

5253
5254
5255
5256
5257
5258
5259
        rc = SQLITE_ERROR;
        sqlite3SetString(&p->zErrMsg, db, 
            "cannot change %s wal mode from within a transaction",
            (eNew==PAGER_JOURNALMODE_WAL ? "into" : "out of")
        );
      }else{
  
        if( eOld==PAGER_JOURNALMODE_WAL ){
          /* If leaving WAL mode, close the log file. If successful, the call
          ** to PagerCloseLog() checkpoints and deletes the write-ahead-log 
          ** file. An EXCLUSIVE lock may still be held on the database file 
          ** after a successful return. 
          */

          rc = sqlite3PagerCloseLog(pPager);
          if( rc!=SQLITE_OK ) goto abort_due_to_error;
          sqlite3PagerJournalMode(pPager, eNew);
        }else{
          sqlite3PagerJournalMode(pPager, PAGER_JOURNALMODE_DELETE);
        }
  

Changes to test/walmode.test.

68
69
70
71
72
73
74


75
76
77
78
79
80
81
..
87
88
89
90
91
92
93


















































94
95
  sqlite3 db test.db
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-3.2 {
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}



do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  execsql { PRAGMA journal_mode = persist }
} {persist}
do_test walmode-4.2 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}
................................................................................
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
} {1 2}
do_test walmode-4.5 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}



















































finish_test








>
>







 







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


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
..
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
  sqlite3 db test.db
  execsql { PRAGMA journal_mode = wal }
} {wal}
do_test walmode-3.2 {
  list $sqlite_sync_count [file exists test.db-wal] [file size test.db-wal]
} {0 1 0}

# Test that changing back to journal_mode=persist works.
#
do_test walmode-4.1 {
  execsql { INSERT INTO t1 VALUES(1, 2) }
  execsql { PRAGMA journal_mode = persist }
} {persist}
do_test walmode-4.2 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}
................................................................................
  sqlite3 db test.db
  execsql { SELECT * FROM t1 }
} {1 2}
do_test walmode-4.5 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {1 0}

# Test that nothing goes wrong if a connection is prevented from changing
# from WAL to rollback mode because a second connection has the database
# open. Or from rollback to WAL.
#
do_test walmode-4.1 {
  sqlite3 db2 test.db
  execsql { PRAGMA main.journal_mode } db2
} {delete}
do_test walmode-4.2 {
  execsql { PRAGMA main.journal_mode = wal } db
} {wal}
do_test walmode-4.3 {
  execsql { SELECT * FROM t1 } db2
} {1 2}
do_test walmode-4.4 {
  catchsql { PRAGMA journal_mode = delete } db
} {1 {database is locked}}
do_test walmode-4.5 {
  execsql { PRAGMA main.journal_mode } db
} {wal}
do_test walmode-4.6 {
  db2 close
  execsql { PRAGMA journal_mode = delete } db
} {delete}
do_test walmode-4.7 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.8 {
  list [file exists test.db-journal] [file exists test.db-wal]
} {0 0}
do_test walmode-4.9 {
  sqlite3 db2 test.db
  execsql {
    BEGIN;
      SELECT * FROM t1;
  } db2
} {1 2}
do_test walmode-4.11 {
  execsql { PRAGMA main.journal_mode } db
} {delete}
do_test walmode-4.10 {
  catchsql { PRAGMA main.journal_mode = wal } db
} {1 {database is locked}}
do_test walmode-4.11 {
  execsql { PRAGMA main.journal_mode } db
} {delete}


catch { db close }
catch { db2 close }
finish_test