SQLite

Check-in [4eb06e843a]
Login

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

Overview
Comment:Fixes for OOM and IO error handling with temp file databases.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tempfiles-lazy-open
Files: files | file ages | folders
SHA1: 4eb06e843af60d5e533793618c6e0e9b7ef7a1a6
User & Date: dan 2016-04-11 18:07:47.205
Context
2016-04-11
18:49
Add extra tests to temptable2.test. (check-in: 7dd9d4c15b user: dan tags: tempfiles-lazy-open)
18:07
Fixes for OOM and IO error handling with temp file databases. (check-in: 4eb06e843a user: dan tags: tempfiles-lazy-open)
09:39
Update this branch with the latest changes from the trunk. (check-in: 982b753d0b user: dan tags: tempfiles-lazy-open)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968

    case PAGER_ERROR:
      /* There must be at least one outstanding reference to the pager if
      ** in ERROR state. Otherwise the pager should have already dropped
      ** back to OPEN state.
      */
      assert( pPager->errCode!=SQLITE_OK );
      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
      break;
  }

  return 1;
}
#endif /* ifndef NDEBUG */








|







954
955
956
957
958
959
960
961
962
963
964
965
966
967
968

    case PAGER_ERROR:
      /* There must be at least one outstanding reference to the pager if
      ** in ERROR state. Otherwise the pager should have already dropped
      ** back to OPEN state.
      */
      assert( pPager->errCode!=SQLITE_OK );
      assert( sqlite3PcacheRefCount(pPager->pPCache)>0 || pPager->tempFile );
      break;
  }

  return 1;
}
#endif /* ifndef NDEBUG */

1815
1816
1817
1818
1819
1820
1821
1822




1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
    pPager->eState = PAGER_OPEN;
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.
  */




  if( pPager->errCode ){
    assert( !MEMDB );
    pager_reset(pPager);
    pPager->changeCountDone = pPager->tempFile;
    pPager->eState = PAGER_OPEN;
    pPager->errCode = SQLITE_OK;
    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
  }

  pPager->journalOff = 0;
  pPager->journalHdr = 0;







|
>
>
>
>
|
<

|







1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827

1828
1829
1830
1831
1832
1833
1834
1835
1836
    pPager->eState = PAGER_OPEN;
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.
  **
  ** Exception: There is no way out of the error state for temp files.
  ** This is because it is not possible to call pager_reset() on a temp
  ** file pager (as this may discard the only copy of some data).  */
  assert( pPager->errCode==SQLITE_OK || !MEMDB );
  if( pPager->tempFile==0 && pPager->errCode ){

    pager_reset(pPager);
    pPager->changeCountDone = 0;
    pPager->eState = PAGER_OPEN;
    pPager->errCode = SQLITE_OK;
    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
  }

  pPager->journalOff = 0;
  pPager->journalHdr = 0;
5030
5031
5032
5033
5034
5035
5036

5037
5038
5039
5040
5041
5042
5043
5044
5045
  /* This routine is only called from b-tree and only when there are no
  ** outstanding pages. This implies that the pager state should either
  ** be OPEN or READER. READER is only possible if the pager is or was in 
  ** exclusive access mode.
  */
  assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
  assert( assert_pager_state(pPager) );

  assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );
  if( NEVER(MEMDB && pPager->errCode) ){ return pPager->errCode; }

  if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
    int bHotJournal = 1;          /* True if there exists a hot journal-file */

    assert( !MEMDB );

    rc = pager_wait_on_lock(pPager, SHARED_LOCK);







>

<







5033
5034
5035
5036
5037
5038
5039
5040
5041

5042
5043
5044
5045
5046
5047
5048
  /* This routine is only called from b-tree and only when there are no
  ** outstanding pages. This implies that the pager state should either
  ** be OPEN or READER. READER is only possible if the pager is or was in 
  ** exclusive access mode.
  */
  assert( sqlite3PcacheRefCount(pPager->pPCache)==0 );
  assert( assert_pager_state(pPager) );
  if( pPager->tempFile && pPager->errCode ) { return pPager->errCode; }
  assert( pPager->eState==PAGER_OPEN || pPager->eState==PAGER_READER );


  if( !pagerUseWal(pPager) && pPager->eState==PAGER_OPEN ){
    int bHotJournal = 1;          /* True if there exists a hot journal-file */

    assert( !MEMDB );

    rc = pager_wait_on_lock(pPager, SHARED_LOCK);
Changes to test/cffault.test.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#
# This file contains fault-injection test cases for the 
# sqlite3_db_cacheflush API.
#

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

# Run the supplied SQL on a copy of the database currently stored on 
# disk in file $dbfile.
proc diskquery {dbfile sql} {
  forcecopy $dbfile dq.db
  sqlite3 dq dq.db







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#
# This file contains fault-injection test cases for the 
# sqlite3_db_cacheflush API.
#

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

# Run the supplied SQL on a copy of the database currently stored on 
# disk in file $dbfile.
proc diskquery {dbfile sql} {
  forcecopy $dbfile dq.db
  sqlite3 dq dq.db
Added test/tempfault.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 2016 April 11
#
# 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 file contains tests for fault-injection when SQLite is used with
# a temp file database.
#

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

sqlite3_memdebug_vfs_oom_test 0

do_faultsim_test 1 -faults oom* -prep {
  sqlite3 db ""
  db eval {
    PRAGMA page_size = 1024;
    CREATE TABLE t1(a, b);
    INSERT INTO t1 VALUES(1, 2);
    INSERT INTO t1 VALUES(3, 4);
  }
} -body {
  execsql { INSERT INTO t1 VALUES(5, 6) }
} -test {
  faultsim_test_result {0 {}}
  set rc [catch { execsql { SELECT * FROM t1 } } msg]
  if {$rc==0 && $msg != "1 2 3 4 5 6" && $msg != "1 2 3 4"} {
    error "data mismatch 1: $msg"
  }
  if {$testrc==0 && $msg != "1 2 3 4 5 6"} {
    error "data mismatch 2: $msg"
  }
  faultsim_integrity_check
}

do_faultsim_test 2 -faults oom* -prep {
  sqlite3 db ""
  db eval {
    PRAGMA page_size = 1024;
    PRAGMA cache_size = 10;
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(b, a);
    WITH x(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<50)
    INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x;
  }
} -body {
  execsql { UPDATE t1 SET a = randomblob(99) }
} -test {
  faultsim_test_result {0 {}}
  faultsim_integrity_check db
}

do_faultsim_test 3 -faults oom* -prep {
  sqlite3 db ""
  db eval {
    PRAGMA page_size = 1024;
    PRAGMA cache_size = 10;
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(b, a);
    WITH x(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<50)
    INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x;
  }
} -body {
  execsql { 
    BEGIN;
      UPDATE t1 SET a = randomblob(99);
      SAVEPOINT abc;
        UPDATE t1 SET a = randomblob(98) WHERE (rowid%10)==0;
      ROLLBACK TO abc;
        UPDATE t1 SET a = randomblob(97) WHERE (rowid%5)==0;
      ROLLBACK TO abc;
    COMMIT;
  }
} -test {
  faultsim_test_result {0 {}}
  faultsim_integrity_check db
}

do_faultsim_test 4 -faults * -prep {
  sqlite3 db ""
  db eval {
    PRAGMA page_size = 1024;
    PRAGMA cache_size = 10;
    CREATE TABLE t1(a, b);
    CREATE INDEX i1 ON t1(b, a);
    WITH x(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<50)
    INSERT INTO t1 SELECT randomblob(100), randomblob(100) FROM x;
  }
} -body {
  execsql { 
    BEGIN;
      UPDATE t1 SET a = randomblob(99);
      SAVEPOINT abc;
        UPDATE t1 SET a = randomblob(98) WHERE (rowid%10)==0;
      ROLLBACK TO abc;
        UPDATE t1 SET a = randomblob(97) WHERE (rowid%5)==0;
      ROLLBACK TO abc;
    COMMIT;
  }
} -test {
  faultsim_test_result {0 {}}
}

sqlite3_memdebug_vfs_oom_test 1
finish_test