/ Check-in [50c8952c]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Fix a spurious SQLITE_CORRUPT error that could occur within a COMMIT of a concurrent transaction.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | begin-concurrent-pnu
Files: files | file ages | folders
SHA3-256: 50c8952c92b9f0c61935fb0df04ed1426d9e266a812071b7bf5b0215c5552757
User & Date: dan 2018-01-02 19:57:26
Context
2018-12-03
19:29
Cherrypick a couple of fixes from begin-concurrent-pnu into this branch. The differences between the two branches are now that this one does not have "PRAGMA noop_update" or the mutex-free PRNG. check-in: a56506b9 user: dan tags: begin-concurrent
2018-01-04
18:36
Fix problem causing free-list corruption when merging free-lists for two concurrent transactions that have both used page X as an in-memory free-list trunk page, where X lies past the end of the initial database images. check-in: dc0fc2aa user: dan tags: begin-concurrent-pnu
2018-01-02
19:57
Fix a spurious SQLITE_CORRUPT error that could occur within a COMMIT of a concurrent transaction. check-in: 50c8952c user: dan tags: begin-concurrent-pnu
2017-12-12
18:17
Merge latest begin-concurrent changes into this branch. check-in: 3fde0b4d user: dan tags: begin-concurrent-pnu
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/btree.c.

4175
4176
4177
4178
4179
4180
4181
4182
4183
4184

4185

4186
4187
4188
4189
4190
4191
4192
....
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
        ** not have shrunk since the transaction was opened. Therefore nHPage
        ** should be set to (pMap->iFirst-1) or greater. */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        /* The current transaction allocated pages pMap->iFirst through
        ** nPage (inclusive) at the end of the database file. Meanwhile,
        ** other transactions have allocated (iFirst..nHPage). So move
        ** pages (iFirst..MIN(nPage,nHPage)) to (MAX(nPage,nHPage)+1).  */
        Pgno iLast = MIN(nPage, nHPage);    /* Last page to move */
        Pgno nCurrent;                      /* Current size of db */

        nCurrent = MAX(nPage, nHPage);

        rc = btreeRelocateRange(pBt, pMap->iFirst, iLast, &nCurrent);

        /* There are now no collisions with the snapshot at the head of the
        ** database file. So at this point it would be possible to write
        ** the transaction out to disk. Before doing so though, attempt to
        ** relocate some of the new pages to free locations within the body
        ** of the database file (i.e. free-list entries). */
................................................................................
  assert( eMode==BTALLOC_ANY || (nearby>0 && REQUIRE_PTRMAP ) );
  pPage1 = pBt->pPage1;
  mxPage = btreePagecount(pBt);
  /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
  ** stores stores the total number of pages on the freelist. */
  n = get4byte(&pPage1->aData[36]);
  testcase( n==mxPage-1 );
  if( ISCONCURRENT==0 && n>=mxPage ){
    return SQLITE_CORRUPT_BKPT;
  }

  /* Ensure page 1 is writable. This function will either change the number
  ** of pages in the free-list or the size of the database file. Since both
  ** of these operations involve modifying page 1 header fields, page 1
  ** will definitely be written by this transaction. If this is an CONCURRENT







|


>

>







 







|







4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
....
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
        ** not have shrunk since the transaction was opened. Therefore nHPage
        ** should be set to (pMap->iFirst-1) or greater. */
        rc = SQLITE_CORRUPT_BKPT;
      }else{
        /* The current transaction allocated pages pMap->iFirst through
        ** nPage (inclusive) at the end of the database file. Meanwhile,
        ** other transactions have allocated (iFirst..nHPage). So move
        ** pages (iFirst..MIN(nPage,nHPage)) to (MAX(nPage,nHPage)+1). */
        Pgno iLast = MIN(nPage, nHPage);    /* Last page to move */
        Pgno nCurrent;                      /* Current size of db */

        nCurrent = MAX(nPage, nHPage);
        pBt->nPage = nCurrent;
        rc = btreeRelocateRange(pBt, pMap->iFirst, iLast, &nCurrent);

        /* There are now no collisions with the snapshot at the head of the
        ** database file. So at this point it would be possible to write
        ** the transaction out to disk. Before doing so though, attempt to
        ** relocate some of the new pages to free locations within the body
        ** of the database file (i.e. free-list entries). */
................................................................................
  assert( eMode==BTALLOC_ANY || (nearby>0 && REQUIRE_PTRMAP ) );
  pPage1 = pBt->pPage1;
  mxPage = btreePagecount(pBt);
  /* EVIDENCE-OF: R-05119-02637 The 4-byte big-endian integer at offset 36
  ** stores stores the total number of pages on the freelist. */
  n = get4byte(&pPage1->aData[36]);
  testcase( n==mxPage-1 );
  if( n>=mxPage ){
    return SQLITE_CORRUPT_BKPT;
  }

  /* Ensure page 1 is writable. This function will either change the number
  ** of pages in the free-list or the size of the database file. Since both
  ** of these operations involve modifying page 1 header fields, page 1
  ** will definitely be written by this transaction. If this is an CONCURRENT

Added test/concurrent6.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
# 2017 May 26
#
# 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.
#
#***********************************************************************
#
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
source $testdir/wal_common.tcl
set ::testprefix concurrent6

ifcapable !concurrent {
  finish_test
  return
}

sqlite3 db2 test.db

do_execsql_test 1.0 {
  PRAGMA page_size = 1024;
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(x);
  CREATE TABLE t2(x);
  CREATE TABLE t3(x);
  CREATE TABLE t4(x);

  INSERT INTO t1 VALUES(zeroblob(1500));
} {wal}

do_execsql_test -db db2 1.1 {
  BEGIN CONCURRENT;
    INSERT INTO t3 VALUES(zeroblob(4000));
    DELETE FROM t1;
}

do_execsql_test 1.2 {
  WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100) 
  INSERT INTO t2 SELECT zeroblob(1000) FROM s;

  WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<100) 
  INSERT INTO t4  SELECT zeroblob(1000) FROM s;

  DELETE FROM t4;
}

do_execsql_test -db db2 1.3 {
  COMMIT;
}


finish_test