/ Check-in [4e894133]
Login

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

Overview
Comment:Have the pager call xReiniter() instead of xDestructor() to restore btree level state after rolling back a page. (CVS 3828)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:4e8941333ef053442877a2a696a2c68d403c7f4d
User & Date: danielk1977 2007-04-09 11:20:54
Context
2007-04-09
12:45
Fix an obscure pager refcnt leak that occurs following a transient I/O error. (CVS 3829) check-in: ce6f56ec user: drh tags: trunk
11:20
Have the pager call xReiniter() instead of xDestructor() to restore btree level state after rolling back a page. (CVS 3828) check-in: 4e894133 user: danielk1977 tags: trunk
2007-04-08
16:52
Work around buggy TCL implementations in the exclusive2 test file. Ticket #2287 (CVS 3827) check-in: 5424fcc5 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
....
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
** 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.325 2007/04/07 15:03:17 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
    ** of an internal error resulting in an automatic call to
    ** sqlite3PagerRollback().
    */
    void *pData;
    /* assert( pPg->nRef==0 || pPg->pgno==1 ); */
    pData = PGHDR_TO_DATA(pPg);
    memcpy(pData, aData, pPager->pageSize);
    if( pPager->xDestructor ){  /*** FIX ME:  Should this be xReinit? ***/
      pPager->xDestructor(pPg, pPager->pageSize);
    }
#ifdef SQLITE_CHECK_PAGES
    pPg->pageHash = pager_pagehash(pPg);
#endif
    CODEC1(pPager, pData, pPg->pgno, 3);

    /* If this was page 1, then restore the value of Pager.iChangeCount */







|







 







|
|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
** 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.326 2007/04/09 11:20:54 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
#include "os.h"
#include "pager.h"
#include <assert.h>
#include <string.h>
................................................................................
    ** of an internal error resulting in an automatic call to
    ** sqlite3PagerRollback().
    */
    void *pData;
    /* assert( pPg->nRef==0 || pPg->pgno==1 ); */
    pData = PGHDR_TO_DATA(pPg);
    memcpy(pData, aData, pPager->pageSize);
    if( pPager->xReiniter ){
      pPager->xReiniter(pPg, pPager->pageSize);
    }
#ifdef SQLITE_CHECK_PAGES
    pPg->pageHash = pager_pagehash(pPg);
#endif
    CODEC1(pPager, pData, pPg->pgno, 3);

    /* If this was page 1, then restore the value of Pager.iChangeCount */

Changes to test/ioerr2.test.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
47
48
49
50
51
52
53

54

55
56
57
58
59
60
61
..
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: ioerr2.test,v 1.1 2007/04/02 16:46:23 danielk1977 Exp $

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

do_test ioerr2-1.1 {
  execsql {
    PRAGMA cache_size = 10;
................................................................................
  # connection. Otherwise, try a ROLLBACK, in case a transaction 
  # is still active.
  set rc [catch {execsql {PRAGMA integrity_check}} msg]
  if {$rc && $msg eq "disk I/O error"} {
    db close
    sqlite3 db test.db
  } else {

    if {$rc} {error $msg}

    catch {execsql ROLLBACK}
  }

  # Check that the database checksum is still $::cksum, and that
  # the integrity-check passes.
  set ck [execsql {SELECT md5sum(a, b) FROM t1}]
  do_test ${testname}.cksum [list set ck $ck] $::cksum
................................................................................
  INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) 
    WHERE (random()%7)==0;
  UPDATE t1 SET a = randstr(400,400), b = randstr(400,400) 
    WHERE (random()%7)==0;
  ROLLBACK;
}


foreach bPersist [list 0 1] {
  set ::go 1
  for {set ::N 1} {$::go} {incr ::N} {
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist $bPersist
    set ::sqlite_io_error_pending $::N

    foreach {::go res} [catchsql $sql] {}
    check_db ioerr2-3.$bPersist.$::N
  }
}

finish_test







|







 







>
|
>







 







>













11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# This file implements regression tests for SQLite library.  The
# focus of this file is testing for correct handling of I/O errors
# such as writes failing because the disk is full.
# 
# The tests in this file use special facilities that are only
# available in the SQLite test fixture.
#
# $Id: ioerr2.test,v 1.2 2007/04/09 11:20:54 danielk1977 Exp $

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

do_test ioerr2-1.1 {
  execsql {
    PRAGMA cache_size = 10;
................................................................................
  # connection. Otherwise, try a ROLLBACK, in case a transaction 
  # is still active.
  set rc [catch {execsql {PRAGMA integrity_check}} msg]
  if {$rc && $msg eq "disk I/O error"} {
    db close
    sqlite3 db test.db
  } else {
    if {$rc || $msg ne "ok"} {
      error $msg
    }
    catch {execsql ROLLBACK}
  }

  # Check that the database checksum is still $::cksum, and that
  # the integrity-check passes.
  set ck [execsql {SELECT md5sum(a, b) FROM t1}]
  do_test ${testname}.cksum [list set ck $ck] $::cksum
................................................................................
  INSERT INTO t1 SELECT randstr(400,400), randstr(400,400) 
    WHERE (random()%7)==0;
  UPDATE t1 SET a = randstr(400,400), b = randstr(400,400) 
    WHERE (random()%7)==0;
  ROLLBACK;
}

breakpoint
foreach bPersist [list 0 1] {
  set ::go 1
  for {set ::N 1} {$::go} {incr ::N} {
    set ::sqlite_io_error_hit 0
    set ::sqlite_io_error_persist $bPersist
    set ::sqlite_io_error_pending $::N

    foreach {::go res} [catchsql $sql] {}
    check_db ioerr2-3.$bPersist.$::N
  }
}

finish_test

Changes to test/lock2.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


25


26
27
28
29
30
31
32
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks between competing processes.
#
# $Id: lock2.test,v 1.6 2005/09/17 16:48:19 drh Exp $


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

# Launch another testfixture process to be controlled by this one. A
# channel name is returned that may be passed as the first argument to proc
# 'testfixture' to execute a command. The child testfixture process is shut
# down by closing the channel.
proc launch_testfixture {} {


  set chan [open "|[file join . testfixture] tf_main.tcl" r+]


  fconfigure $chan -buffering line
  return $chan
}

# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
proc testfixture {chan cmd} {







|










>
>
|
>
>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is database locks between competing processes.
#
# $Id: lock2.test,v 1.7 2007/04/09 11:20:54 danielk1977 Exp $


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

# Launch another testfixture process to be controlled by this one. A
# channel name is returned that may be passed as the first argument to proc
# 'testfixture' to execute a command. The child testfixture process is shut
# down by closing the channel.
proc launch_testfixture {} {
  set prg [info nameofexec]
  if {$prg eq ""} {
    set prg [file join . testfixture]
  }
  set chan [open "|$prg tf_main.tcl" r+]
  fconfigure $chan -buffering line
  return $chan
}

# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
proc testfixture {chan cmd} {