/ Check-in [443cf105]
Login

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

Overview
Comment:If a pager is already in the error-state when CommitPhaseOne() is called, exit early. (CVS 5134)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 443cf1056c73ae89d0efcc7a462455c078b3a4a8
User & Date: danielk1977 2008-05-15 11:08:08
Context
2008-05-15
17:48
Add the "page_count" pragma. Returns a single integer - the number of pages in the specified database file. (CVS 5135) check-in: eb6985e6 user: danielk1977 tags: trunk
11:08
If a pager is already in the error-state when CommitPhaseOne() is called, exit early. (CVS 5134) check-in: 443cf105 user: danielk1977 tags: trunk
09:07
Fix a test script bug - not all database handles were being closed by ioerr5.test. (CVS 5133) check-in: 47652e7b 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
....
4609
4610
4611
4612
4613
4614
4615




4616
4617
4618
4619
4620
4621
4622
** 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.447 2008/05/15 08:34:54 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
................................................................................
int sqlite3PagerCommitPhaseOne(
  Pager *pPager, 
  const char *zMaster, 
  Pgno nTrunc,
  int noSync
){
  int rc = SQLITE_OK;





  /* If no changes have been made, we can leave the transaction early.
  */
  if( pPager->dbModified==0 &&
        (pPager->journalMode!=PAGER_JOURNALMODE_DELETE ||
          pPager->exclusiveMode!=0) ){
    assert( pPager->dirtyCache==0 || pPager->journalOpen==0 );







|







 







>
>
>
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
** 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.448 2008/05/15 11:08:08 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include <assert.h>
#include <string.h>

/*
................................................................................
int sqlite3PagerCommitPhaseOne(
  Pager *pPager, 
  const char *zMaster, 
  Pgno nTrunc,
  int noSync
){
  int rc = SQLITE_OK;

  if( pPager->errCode ){
    return pPager->errCode;
  }

  /* If no changes have been made, we can leave the transaction early.
  */
  if( pPager->dbModified==0 &&
        (pPager->journalMode!=PAGER_JOURNALMODE_DELETE ||
          pPager->exclusiveMode!=0) ){
    assert( pPager->dirtyCache==0 || pPager->journalOpen==0 );

Changes to test/ioerr5.test.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
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
...
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
148
149
150
151
152
#***********************************************************************
#
# This file tests that if sqlite3_release_memory() is called to reclaim
# memory from a pager that is in the error-state, SQLite does not 
# incorrectly write dirty pages out to the database (not safe to do
# once the pager is in error state).
#
# $Id: ioerr5.test,v 1.2 2008/05/15 09:07:56 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !memorymanage||!shared_cache {
  finish_test
  return
................................................................................
  for {set iFail 1} {$iFail<200} {incr iFail} {
    sqlite3_soft_heap_limit 1048576
    opendatabases
    execsql { pragma locking_mode=exclusive }
    set nRow [db one {SELECT count(*) FROM a}]
  
    # Dirty (at least) one of the pages in the cache.
    do_test ioerr5-$locking_mode-$iFail.1 {
      execsql {
        BEGIN EXCLUSIVE;
        INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
      }
    } {}
  
    # Now try to commit the transaction. Cause an IO error to occur
    # within this operation, which moves the pager into the error state.
    #
    set ::sqlite_io_error_persist 1
    set ::sqlite_io_error_pending $iFail
    do_test ioerr5-$locking_mode-$iFail.2 {
      set rc [catchsql {COMMIT}]
      list
    } {}
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist 0
    set ::sqlite_io_error_pending 0
  
................................................................................
    close $fd

    # Set a very low soft-limit and then try to compile an SQL statement 
    # from UTF-16 text. To do this, SQLite will need to reclaim memory
    # from the pager that is in error state. Including that associated
    # with the dirty page.
    #
    do_test ioerr5-$locking_mode-$iFail.3 {
      sqlite3_soft_heap_limit 1024
      compilesql16 "SELECT 10"
      set bt [btree_from_db db]
      array set stats [btree_pager_stats $bt]
      set stats(page)
    } {0}

    # Ensure that nothing was written to the database while reclaiming
    # memory from the pager in error state.
    #
    do_test ioerr5-$locking_mode-$iFail.4 {
      set fd [open test.db]
      fconfigure $fd -translation binary -encoding binary
      set zDatabase2 [read $fd]
      close $fd
      expr {$zDatabase eq $zDatabase2}
    } {1}
  
    if {$rc eq [list 0 {}]} {
      do_test ioerr5-$locking_mode-$iFail.3 {
        execsql { SELECT count(*) FROM a }
      } [expr $nRow+1]
      break
    }
  }
}


















































# Make sure this test script doesn't leave any files open.
#
do_test ioerr5-2.X {
  catch { db close }
  catch { db2 close }
  set sqlite_open_file_count







|







 







|











|







 







|










|








|






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







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
..
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
...
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#***********************************************************************
#
# This file tests that if sqlite3_release_memory() is called to reclaim
# memory from a pager that is in the error-state, SQLite does not 
# incorrectly write dirty pages out to the database (not safe to do
# once the pager is in error state).
#
# $Id: ioerr5.test,v 1.3 2008/05/15 11:08:08 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !memorymanage||!shared_cache {
  finish_test
  return
................................................................................
  for {set iFail 1} {$iFail<200} {incr iFail} {
    sqlite3_soft_heap_limit 1048576
    opendatabases
    execsql { pragma locking_mode=exclusive }
    set nRow [db one {SELECT count(*) FROM a}]
  
    # Dirty (at least) one of the pages in the cache.
    do_test ioerr5-1.$locking_mode-$iFail.1 {
      execsql {
        BEGIN EXCLUSIVE;
        INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
      }
    } {}
  
    # Now try to commit the transaction. Cause an IO error to occur
    # within this operation, which moves the pager into the error state.
    #
    set ::sqlite_io_error_persist 1
    set ::sqlite_io_error_pending $iFail
    do_test ioerr5-1.$locking_mode-$iFail.2 {
      set rc [catchsql {COMMIT}]
      list
    } {}
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist 0
    set ::sqlite_io_error_pending 0
  
................................................................................
    close $fd

    # Set a very low soft-limit and then try to compile an SQL statement 
    # from UTF-16 text. To do this, SQLite will need to reclaim memory
    # from the pager that is in error state. Including that associated
    # with the dirty page.
    #
    do_test ioerr5-1.$locking_mode-$iFail.3 {
      sqlite3_soft_heap_limit 1024
      compilesql16 "SELECT 10"
      set bt [btree_from_db db]
      array set stats [btree_pager_stats $bt]
      set stats(page)
    } {0}

    # Ensure that nothing was written to the database while reclaiming
    # memory from the pager in error state.
    #
    do_test ioerr5-1.$locking_mode-$iFail.4 {
      set fd [open test.db]
      fconfigure $fd -translation binary -encoding binary
      set zDatabase2 [read $fd]
      close $fd
      expr {$zDatabase eq $zDatabase2}
    } {1}
  
    if {$rc eq [list 0 {}]} {
      do_test ioerr5.1-$locking_mode-$iFail.3 {
        execsql { SELECT count(*) FROM a }
      } [expr $nRow+1]
      break
    }
  }
}

# Make sure this test script doesn't leave any files open.
#
do_test ioerr5-1.X {
  catch { db close }
  catch { db2 close }
  set sqlite_open_file_count
} 0

do_test ioerr5-2.0 {
  sqlite3 db test.db
  execsql { CREATE INDEX i1 ON a(id, name); }
} {}

foreach locking_mode {exclusive normal} {
  for {set iFail 1} {$iFail<200} {incr iFail} {
    sqlite3_soft_heap_limit 1048576
    opendatabases
    execsql { pragma locking_mode=exclusive }
    set nRow [db one {SELECT count(*) FROM a}]
  
    do_test ioerr5-2.$locking_mode-$iFail.1 {
      execsql {
        BEGIN EXCLUSIVE;
        INSERT INTO a VALUES(1, 'ABCDEFGHIJKLMNOP');
      }
    } {}

    set ::sqlite_io_error_persist 1
    set ::sqlite_io_error_pending $iFail

    sqlite3_release_memory 10000

    set error_hit $::sqlite_io_error_hit
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist 0
    set ::sqlite_io_error_pending 0
    if {$error_hit} {
      do_test ioerr5-2.$locking_mode-$iFail.3a {
        catchsql COMMIT
      } {1 {disk I/O error}}
    } else {
      do_test ioerr5-2.$locking_mode-$iFail.3b {
        execsql COMMIT
      } {}
      break
    }
  }
}

# Make sure this test script doesn't leave any files open.
#
do_test ioerr5-2.X {
  catch { db close }
  catch { db2 close }
  set sqlite_open_file_count