SQLite

Check-in [1e53e382e5]
Login

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

Overview
Comment:Add a test script for ticket #2565. Change the assert() in pager.c into a testcase() macro. (CVS 6142)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1e53e382e5030de4d908098bf77af053dd81f0c5
User & Date: drh 2009-01-08 15:24:02.000
Context
2009-01-08
17:50
Fix a couple of potential corruption problems in pager.c. (CVS 6143) (check-in: 5a39525ba3 user: danielk1977 tags: trunk)
15:24
Add a test script for ticket #2565. Change the assert() in pager.c into a testcase() macro. (CVS 6142) (check-in: 1e53e382e5 user: drh tags: trunk)
14:36
Allow database files to be created in the root directory on unix. Ticket #3570. (CVS 6141) (check-in: 81014334ad user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.540 2009/01/07 18:08:49 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/







|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
** 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.541 2009/01/08 15:24:02 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
    ** The third term of the test was added to fix ticket #2565.
    ** When rolling back a hot journal, nRec==0 always means that the next
    ** chunk of the journal contains zero pages to be rolled back.  But
    ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
    ** the journal, it means that the journal might contain additional
    ** pages that need to be rolled back and that the number of pages 
    ** should be computed based on the journal file size.
    **
    ** 2009-01-07:  We think #2565 is now unreachable due to changes
    ** in the pcache.  The assert that follows will fire if we are wrong.
    */
    assert( !(nRec==0 && !isHot
         && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)!=pPager->journalOff
         && ((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager))>0
         && pagerNextJournalPageIsValid(pPager))
    );
    if( nRec==0 && !isHot &&
        pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
      nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
    }

    /* If this is the first header read from the journal, truncate the







<
<
<

|


|







1643
1644
1645
1646
1647
1648
1649



1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
    ** The third term of the test was added to fix ticket #2565.
    ** When rolling back a hot journal, nRec==0 always means that the next
    ** chunk of the journal contains zero pages to be rolled back.  But
    ** when doing a ROLLBACK and the nRec==0 chunk is the last chunk in
    ** the journal, it means that the journal might contain additional
    ** pages that need to be rolled back and that the number of pages 
    ** should be computed based on the journal file size.



    */
    testcase( nRec==0 && !isHot
         && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)!=pPager->journalOff
         && ((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager))>0
         && pagerNextJournalPageIsValid(pPager)
    );
    if( nRec==0 && !isHot &&
        pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){
      nRec = (int)((szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager));
    }

    /* If this is the first header read from the journal, truncate the
Added test/tkt2565.test.




















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 2009 January 8
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# This script attempts to reproduce the circumstances of ticket #2565.
#
# More specifically, this script attempts to generate rollback journals
# that contain headers with nRec==0 that are followed by additional
# valid headers.
#
# $Id: tkt2565.test,v 1.1 2009/01/08 15:24:02 drh Exp $

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

# Use the alternative pcache and rig it to call pagerStress()
# very frequently.
#
db close
sqlite3_shutdown
sqlite3_config_alt_pcache 1 100 0 1

# Open two database connections to database "test.db".
#
proc reopen_database {} {
  catch {db close}
  sqlite3 db test.db
  db cache size 0
  execsql {
    pragma page_size=512;
    pragma auto_vacuum=2;
    pragma cache_size=16;
  }
}

# Open two database connections and create a single table in the db.
#
do_test tkt2565-1.0 {
  reopen_database
  execsql { CREATE TABLE A(Id INTEGER, Name TEXT) }
} {}

for {set iFail 1} {$iFail<200} {incr iFail} {
  reopen_database
  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 tkt2565-1.$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 tkt2565-1.$iFail.2 {
    set rc [catchsql {COMMIT}]
    list
  } {}
  set ::sqlite_io_error_persist 0
  set ::sqlite_io_error_pending 0
  if {!$::sqlite_io_error_hit} break
  set ::sqlite_io_error_hit 0
}

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

# Restore the pcache configuration for subsequent tests.
#
sqlite3_shutdown
sqlite3_config_alt_pcache 0

finish_test