/ Check-in [8c1d0c6a]
Login

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

Overview
Comment:Make sure a ROLLBACK that follows an incremental vacuum works. Ticket #3761. (CVS 6416)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 8c1d0c6ad9646816eb8ca15b7df4e79b9b1b59ee
User & Date: drh 2009-03-31 02:54:40
Context
2009-03-31
03:41
Fix compiler warnings from gcc and MSVC; Correct typo in select.c; (CVS 6417) check-in: 76851417 user: shane tags: trunk
02:54
Make sure a ROLLBACK that follows an incremental vacuum works. Ticket #3761. (CVS 6416) check-in: 8c1d0c6a user: drh tags: trunk
01:32
Remove two unused lines from pcache.c. (CVS 6415) check-in: d5cab05c 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
....
1495
1496
1497
1498
1499
1500
1501

1502
1503
1504
1505
1506
1507
1508
....
5012
5013
5014
5015
5016
5017
5018

5019
5020
5021
5022
5023
5024
5025
....
5070
5071
5072
5073
5074
5075
5076

5077
5078
5079
5080
5081
5082
5083
....
5111
5112
5113
5114
5115
5116
5117













5118
5119
5120
5121
5122
5123
5124
** 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.575 2009/03/28 10:54:23 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
  ** the page is marked as needSync==0.
  **
  ** 2008-04-14:  When attempting to vacuum a corrupt database file, it
  ** is possible to fail a statement on a database that does not yet exist.
  ** Do not attempt to write if database file has never been opened.
  */
  pPg = pager_lookup(pPager, pgno);

  PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
               PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData),
               (isMainJrnl?"main-journal":"sub-journal")
  ));
  if( (pPager->state>=PAGER_EXCLUSIVE)
   && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC))
   && isOpen(pPager->fd)
................................................................................
** This function may return SQLITE_NOMEM or an IO error code if an error
** occurs. Otherwise, it returns SQLITE_OK.
*/
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
  PgHdr *pPgOld;               /* The page being overwritten. */
  Pgno needSyncPgno = 0;       /* Old value of pPg->pgno, if sync is required */
  int rc;                      /* Return code */


  assert( pPg->nRef>0 );

  /* If the page being moved is dirty and has not been saved by the latest
  ** savepoint, then save the current contents of the page into the 
  ** sub-journal now. This is required to handle the following scenario:
  **
................................................................................
  pPg->flags &= ~PGHDR_NEED_SYNC;
  pPgOld = pager_lookup(pPager, pgno);
  assert( !pPgOld || pPgOld->nRef==1 );
  if( pPgOld ){
    pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
  }


  sqlite3PcacheMove(pPg, pgno);
  if( pPgOld ){
    sqlite3PcacheDrop(pPgOld);
  }

  sqlite3PcacheMakeDirty(pPg);
  pPager->dbModified = 1;
................................................................................
    }
    pPager->needSync = 1;
    assert( pPager->noSync==0 && !MEMDB );
    pPgHdr->flags |= PGHDR_NEED_SYNC;
    sqlite3PcacheMakeDirty(pPgHdr);
    sqlite3PagerUnref(pPgHdr);
  }














  return SQLITE_OK;
}
#endif

/*
** Return a pointer to the data for the specified page.







|







 







>







 







>







 







>







 







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







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
....
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
....
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
....
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
....
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
** 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.576 2009/03/31 02:54:40 drh Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"

/*
** Macros for troubleshooting.  Normally turned off
*/
................................................................................
  ** the page is marked as needSync==0.
  **
  ** 2008-04-14:  When attempting to vacuum a corrupt database file, it
  ** is possible to fail a statement on a database that does not yet exist.
  ** Do not attempt to write if database file has never been opened.
  */
  pPg = pager_lookup(pPager, pgno);
  assert( pPg || !MEMDB );
  PAGERTRACE(("PLAYBACK %d page %d hash(%08x) %s\n",
               PAGERID(pPager), pgno, pager_datahash(pPager->pageSize, aData),
               (isMainJrnl?"main-journal":"sub-journal")
  ));
  if( (pPager->state>=PAGER_EXCLUSIVE)
   && (pPg==0 || 0==(pPg->flags&PGHDR_NEED_SYNC))
   && isOpen(pPager->fd)
................................................................................
** This function may return SQLITE_NOMEM or an IO error code if an error
** occurs. Otherwise, it returns SQLITE_OK.
*/
int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno, int isCommit){
  PgHdr *pPgOld;               /* The page being overwritten. */
  Pgno needSyncPgno = 0;       /* Old value of pPg->pgno, if sync is required */
  int rc;                      /* Return code */
  Pgno origPgno;               /* The original page number */

  assert( pPg->nRef>0 );

  /* If the page being moved is dirty and has not been saved by the latest
  ** savepoint, then save the current contents of the page into the 
  ** sub-journal now. This is required to handle the following scenario:
  **
................................................................................
  pPg->flags &= ~PGHDR_NEED_SYNC;
  pPgOld = pager_lookup(pPager, pgno);
  assert( !pPgOld || pPgOld->nRef==1 );
  if( pPgOld ){
    pPg->flags |= (pPgOld->flags&PGHDR_NEED_SYNC);
  }

  origPgno = pPg->pgno;
  sqlite3PcacheMove(pPg, pgno);
  if( pPgOld ){
    sqlite3PcacheDrop(pPgOld);
  }

  sqlite3PcacheMakeDirty(pPg);
  pPager->dbModified = 1;
................................................................................
    }
    pPager->needSync = 1;
    assert( pPager->noSync==0 && !MEMDB );
    pPgHdr->flags |= PGHDR_NEED_SYNC;
    sqlite3PcacheMakeDirty(pPgHdr);
    sqlite3PagerUnref(pPgHdr);
  }

  /*
  ** For an in-memory database, make sure the original page continues
  ** to exist, in case the transaction needs to roll back.  We allocate
  ** the page now, instead of at rollback, because we can better deal
  ** with an out-of-memory error now.  Ticket #3761.
  */
  if( MEMDB ){
    DbPage *pNew;
    rc = sqlite3PagerAcquire(pPager, origPgno, &pNew, 1);
    if( rc!=SQLITE_OK ) return rc;
    sqlite3PagerUnref(pNew);
  }

  return SQLITE_OK;
}
#endif

/*
** Return a pointer to the data for the specified page.

Added test/tkt3761.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
# 2009 March 30
#
# 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.
#
#***********************************************************************
#
# Ticket #3761:  Make sure that an incremental vacuum on an in-memory
# database can be rolled back.
#
# $Id: tkt3761.test,v 1.1 2009/03/31 02:54:40 drh Exp $

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

do_test tkt3761-1.1 {
  db close
  sqlite3 db :memory:
  db eval {
    PRAGMA auto_vacuum=INCREMENTAL;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(zeroblob(900));
    INSERT INTO t1 VALUES(zeroblob(900));
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    INSERT INTO t1 SELECT x FROM t1;
    BEGIN;
    DELETE FROM t1 WHERE rowid%2;
    PRAGMA incremental_vacuum(4);
    ROLLBACK;
  }
  db eval {PRAGMA integrity_check}
} {ok}

finish_test