SQLite

Check-in [3d61da4a76]
Login

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

Overview
Comment:Fix some problems to do with temp-file databases and recovering from IO and SQLITE_FULL errors.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | tempfiles-25
Files: files | file ages | folders
SHA1: 3d61da4a76af8c9c2a293df085f3ed5a7bb447df
User & Date: dan 2016-04-23 14:55:28.020
Context
2016-04-23
17:24
Fix a problem with mixing temp-files and mmap-mode. (check-in: c80c5c62b2 user: dan tags: tempfiles-25)
14:55
Fix some problems to do with temp-file databases and recovering from IO and SQLITE_FULL errors. (check-in: 3d61da4a76 user: dan tags: tempfiles-25)
2016-04-21
15:24
Add a function prototype in order to fix a compiler warning. (check-in: 49aec9718d user: drh tags: tempfiles-25)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
1820
1821
1822
1823
1824
1825
1826

1827
1828
1829
1830

1831

1832

1833
1834
1835
1836
1837
1838
1839
  ** 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;
  pPager->setMaster = 0;
}








>
|
|
|
|
>
|
>

>







1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
  ** 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->errCode ){
    if( pPager->tempFile==0 ){
      pager_reset(pPager);
      pPager->changeCountDone = 0;
      pPager->eState = PAGER_OPEN;
    }else{
      pPager->eState = (isOpen(pPager->jfd) ? PAGER_OPEN : PAGER_READER);
    }
    if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0);
    pPager->errCode = SQLITE_OK;
  }

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

2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
  */
  if( pagerUseWal(pPager) ){
    pPg = 0;
  }else{
    pPg = sqlite3PagerLookup(pPager, pgno);
  }
  assert( pPg || !MEMDB );
  assert( pPager->eState!=PAGER_OPEN || pPg==0 );
  PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
           PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
           (isMainJrnl?"main-journal":"sub-journal")
  ));
  if( isMainJrnl ){
    isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
  }else{







|







2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
  */
  if( pagerUseWal(pPager) ){
    pPg = 0;
  }else{
    pPg = sqlite3PagerLookup(pPager, pgno);
  }
  assert( pPg || !MEMDB );
  assert( pPager->eState!=PAGER_OPEN || pPg==0 || pPager->tempFile );
  PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
           PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, (u8*)aData),
           (isMainJrnl?"main-journal":"sub-journal")
  ));
  if( isMainJrnl ){
    isSynced = pPager->noSync || (*pOffset <= pPager->journalHdr);
  }else{
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060

5061
5062
5063
5064
5065

5066
5067
5068
5069
5070
5071
5072
*/
int sqlite3PagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;                /* Return code */

  /* 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);
    if( rc!=SQLITE_OK ){
      assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
      goto failed;
    }








|
<


<

>





>







5052
5053
5054
5055
5056
5057
5058
5059

5060
5061

5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
*/
int sqlite3PagerSharedLock(Pager *pPager){
  int rc = SQLITE_OK;                /* Return code */

  /* 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 );
  assert( pPager->errCode==SQLITE_OK );

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

    assert( !MEMDB );
    assert( pPager->tempFile==0 || pPager->eLock==EXCLUSIVE_LOCK );

    rc = pager_wait_on_lock(pPager, SHARED_LOCK);
    if( rc!=SQLITE_OK ){
      assert( pPager->eLock==NO_LOCK || pPager->eLock==UNKNOWN_LOCK );
      goto failed;
    }

5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
      ** probably did not sync it and we are required to always sync
      ** the journal before playing it back.
      */
      if( isOpen(pPager->jfd) ){
        assert( rc==SQLITE_OK );
        rc = pagerSyncHotJournal(pPager);
        if( rc==SQLITE_OK ){
          rc = pager_playback(pPager, 1);
          pPager->eState = PAGER_OPEN;
        }
      }else if( !pPager->exclusiveMode ){
        pagerUnlockDb(pPager, SHARED_LOCK);
      }

      if( rc!=SQLITE_OK ){







|







5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
      ** probably did not sync it and we are required to always sync
      ** the journal before playing it back.
      */
      if( isOpen(pPager->jfd) ){
        assert( rc==SQLITE_OK );
        rc = pagerSyncHotJournal(pPager);
        if( rc==SQLITE_OK ){
          rc = pager_playback(pPager, !pPager->tempFile);
          pPager->eState = PAGER_OPEN;
        }
      }else if( !pPager->exclusiveMode ){
        pagerUnlockDb(pPager, SHARED_LOCK);
      }

      if( rc!=SQLITE_OK ){
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
  }

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
    rc = pagerBeginReadTransaction(pPager);
  }

  if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    rc = pagerPagecount(pPager, &pPager->dbSize);
  }

 failed:
  if( rc!=SQLITE_OK ){
    assert( !MEMDB );
    pager_unlock(pPager);







|







5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
  }

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
    rc = pagerBeginReadTransaction(pPager);
  }

  if( pPager->tempFile==0 && pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    rc = pagerPagecount(pPager, &pPager->dbSize);
  }

 failed:
  if( rc!=SQLITE_OK ){
    assert( !MEMDB );
    pager_unlock(pPager);
Changes to test/tempfault.test.
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#

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);
  }







|

|







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#

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 * -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);
  }
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
  }
  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)







|






|









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







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
  }
  if {$testrc==0 && $msg != "1 2 3 4 5 6"} {
    error "data mismatch 2: $msg"
  }
  faultsim_integrity_check
}

do_faultsim_test 2 -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<100)
    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
}

catch { db close }
do_faultsim_test 2.1 -faults * -prep {
  if {[info commands db]==""} {
    sqlite3 db ""
    execsql {
      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<100)
          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 * -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)