SQLite

Check-in [dc0fc2aa7c]
Login

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

Overview
Comment: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.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | begin-concurrent-pnu
Files: files | file ages | folders
SHA3-256: dc0fc2aa7cbefeb5f0ba8c992fd3e9adcfb5a4d61e2321c1bd93f4d36ba9aafc
User & Date: dan 2018-01-04 18:36:39.212
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: a56506b938 user: dan tags: begin-concurrent)
2018-02-20
21:00
Add extra code to log details when corruption is detected in the pointer-map structure maintained by the b-tree layer in begin-concurrent transactions. (check-in: 5702337160 user: dan tags: begin-concurrent-pnu)
2018-01-23
01:56
Enhance the PRAGMA noop_update statement so that the behavior persists across reprepare operations. (Leaf check-in: c25da6de1d user: drh tags: noop-update-reprepare)
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: dc0fc2aa7c 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: 50c8952c92 user: dan tags: begin-concurrent-pnu)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/btree.c.
4091
4092
4093
4094
4095
4096
4097
4098



4099
4100
4101
4102
4103
4104
4105

    if( iPg==PENDING_BYTE_PAGE(pBt) ) continue;
    pEntry = &pMap->aPtr[iPg - pMap->iFirst];

    if( pEntry->eType==PTRMAP_FREEPAGE ){
      Pgno dummy;
      rc = allocateBtreePage(pBt, &pFree, &dummy, iPg, BTALLOC_EXACT);
      releasePage(pFree);



      assert( rc!=SQLITE_OK || dummy==iPg );
    }else if( pnCurrent ){
      btreeGetPage(pBt, iPg, &pPg, 0);
      assert( sqlite3PagerIswriteable(pPg->pDbPage) );
      assert( sqlite3PagerPageRefcount(pPg->pDbPage)==1 );
      iNew = ++(*pnCurrent);
      if( iNew==PENDING_BYTE_PAGE(pBt) ) iNew = ++(*pnCurrent);







|
>
>
>







4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108

    if( iPg==PENDING_BYTE_PAGE(pBt) ) continue;
    pEntry = &pMap->aPtr[iPg - pMap->iFirst];

    if( pEntry->eType==PTRMAP_FREEPAGE ){
      Pgno dummy;
      rc = allocateBtreePage(pBt, &pFree, &dummy, iPg, BTALLOC_EXACT);
      if( pFree ){
        assert( sqlite3PagerPageRefcount(pFree->pDbPage)==1 );
        sqlite3PcacheDrop(pFree->pDbPage);
      }
      assert( rc!=SQLITE_OK || dummy==iPg );
    }else if( pnCurrent ){
      btreeGetPage(pBt, iPg, &pPg, 0);
      assert( sqlite3PagerIswriteable(pPg->pDbPage) );
      assert( sqlite3PagerPageRefcount(pPg->pDbPage)==1 );
      iNew = ++(*pnCurrent);
      if( iNew==PENDING_BYTE_PAGE(pBt) ) iNew = ++(*pnCurrent);
Added test/concurrent7.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
# 2018 Jan 5
#
# 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
set ::testprefix concurrent7

sqlite3 db2 test.db

do_execsql_test 1 {
  PRAGMA journal_mode = wal;
  CREATE TABLE t1(x);
  CREATE TABLE t2(x);
} {wal}

do_execsql_test -db db2 2 {
  SELECT * FROM t1;
}

do_execsql_test 3 {
  BEGIN CONCURRENT;
    INSERT INTO t1 VALUES(randomblob(1500));
    INSERT INTO t1 VALUES(randomblob(1500));
    DELETE FROM t1 WHERE rowid = 1;
}

do_execsql_test -db db2 4 {
  INSERT INTO t2 VALUES(randomblob(1500));
  INSERT INTO t2 VALUES(randomblob(1500));
  INSERT INTO t2 VALUES(randomblob(1500));
  INSERT INTO t2 VALUES(randomblob(1500));
  DELETE FROM t2 WHERE rowid IN (1, 2);
}

do_execsql_test 5 {
  COMMIT;
  PRAGMA integrity_check;
} {ok}

finish_test