Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Additional test coverage in btree.c. Added corruption tests for the ptrmap pages of an autovacuumed database (corrupt8.test). (CVS 5391) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
620b472133438607c412e0c21d2a2760 |
User & Date: | drh 2008-07-11 02:21:41.000 |
Context
2008-07-11
| ||
03:34 | Make the btree layer robust when faced with a corrupt database that contains duplicate entries on the freelist. Ticket #3209. (CVS 5392) (check-in: 30825f74d6 user: drh tags: trunk) | |
02:21 | Additional test coverage in btree.c. Added corruption tests for the ptrmap pages of an autovacuumed database (corrupt8.test). (CVS 5391) (check-in: 620b472133 user: drh tags: trunk) | |
2008-07-10
| ||
20:41 | Fix a bug in the mutex-testing logic introduced by check-in (5389). (CVS 5390) (check-in: 8fc462b6b7 user: drh tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $Id: btree.c,v 1.476 2008/07/11 02:21:41 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ** SQLITE_LOCKED if not. */ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the | > > | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | ** SQLITE_LOCKED if not. */ static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the |
︙ | ︙ | |||
121 122 123 124 125 126 127 | ** (BtShared.pLock). ** ** To summarize: If the ReadUncommitted flag is set, then read cursors do ** not create or respect table locks. The locking procedure for a ** write-cursor does not change. */ if( | < | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | ** (BtShared.pLock). ** ** To summarize: If the ReadUncommitted flag is set, then read cursors do ** not create or respect table locks. The locking procedure for a ** write-cursor does not change. */ if( 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK || iTab==MASTER_ROOT ){ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p && pIter->iTable==iTab && (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ |
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | */ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pLock = 0; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } assert( SQLITE_OK==queryTableLock(p, iTable, eLock) ); /* If the read-uncommitted flag is set and a read-lock is requested, ** return early without adding an entry to the BtShared.pLock list. See ** comment in function queryTableLock() for more info on handling ** the ReadUncommitted flag. */ if( | > > < | 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | */ static int lockTable(Btree *p, Pgno iTable, u8 eLock){ BtShared *pBt = p->pBt; BtLock *pLock = 0; BtLock *pIter; assert( sqlite3BtreeHoldsMutex(p) ); assert( eLock==READ_LOCK || eLock==WRITE_LOCK ); assert( p->db!=0 ); /* This is a no-op if the shared-cache is not enabled */ if( !p->sharable ){ return SQLITE_OK; } assert( SQLITE_OK==queryTableLock(p, iTable, eLock) ); /* If the read-uncommitted flag is set and a read-lock is requested, ** return early without adding an entry to the BtShared.pLock list. See ** comment in function queryTableLock() for more info on handling ** the ReadUncommitted flag. */ if( (p->db->flags&SQLITE_ReadUncommitted) && (eLock==READ_LOCK) && iTable!=MASTER_ROOT ){ return SQLITE_OK; } |
︙ | ︙ | |||
625 626 627 628 629 630 631 | #ifndef SQLITE_OMIT_AUTOVACUUM /* ** If the cell pCell, part of page pPage contains a pointer ** to an overflow page, insert an entry into the pointer-map ** for the overflow page. */ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ | < | > | | | | | < | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | #ifndef SQLITE_OMIT_AUTOVACUUM /* ** If the cell pCell, part of page pPage contains a pointer ** to an overflow page, insert an entry into the pointer-map ** for the overflow page. */ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){ CellInfo info; assert( pCell!=0 ); sqlite3BtreeParseCellPtr(pPage, pCell, &info); assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload ); if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){ Pgno ovfl = get4byte(&pCell[info.iOverflow]); return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno); } return SQLITE_OK; } /* ** If the cell with index iCell on page pPage contains a pointer ** to an overflow page, insert an entry into the pointer-map ** for the overflow page. |
︙ | ︙ | |||
707 708 709 710 711 712 713 | memset(&data[addr], 0, brk-addr); } /* ** Allocate nByte bytes of space on a page. ** ** Return the index into pPage->aData[] of the first byte of | | | | > | | 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | memset(&data[addr], 0, brk-addr); } /* ** Allocate nByte bytes of space on a page. ** ** Return the index into pPage->aData[] of the first byte of ** the new allocation. The caller guarantees that there is enough ** space. This routine will never fail. ** ** If the page contains nBytes of free space but does not contain ** nBytes of contiguous free space, then this routine automatically ** calls defragementPage() to consolidate all free space before ** allocating the new chunk. */ static int allocateSpace(MemPage *pPage, int nByte){ int addr, pc, hdr; int size; int nFrag; int top; int nCell; int cellOffset; unsigned char *data; data = pPage->aData; assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( pPage->pBt ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( nByte>=0 ); /* Minimum cell size is 4 */ assert( pPage->nFree>=nByte ); assert( pPage->nOverflow==0 ); pPage->nFree -= nByte; hdr = pPage->hdrOffset; nFrag = data[hdr+7]; if( nFrag<60 ){ /* Search the freelist looking for a slot big enough to satisfy the ** space request. */ |
︙ | ︙ |
Added test/corrupt8.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 | # 2008 June 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 implements regression tests for SQLite library. # # This file implements tests to make sure SQLite does not crash or # segfault if it sees a corrupt database file. It specifically focuses # on corrupt pointer map pages. # # $Id: corrupt8.test,v 1.1 2008/07/11 02:21:41 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # We must have the page_size pragma for these tests to work. # ifcapable !pager_pragmas||!autovacuum { finish_test return } # Create a database to work with. # do_test corrupt8-1.1 { execsql { PRAGMA auto_vacuum=1; PRAGMA page_size=1024; CREATE TABLE t1(x); INSERT INTO t1(x) VALUES(1); INSERT INTO t1(x) VALUES(2); INSERT INTO t1(x) SELECT x+2 FROM t1; INSERT INTO t1(x) SELECT x+4 FROM t1; INSERT INTO t1(x) SELECT x+8 FROM t1; INSERT INTO t1(x) SELECT x+16 FROM t1; INSERT INTO t1(x) SELECT x+32 FROM t1; INSERT INTO t1(x) SELECT x+64 FROM t1; INSERT INTO t1(x) SELECT x+128 FROM t1; INSERT INTO t1(x) SELECT x+256 FROM t1; CREATE TABLE t2(a,b); INSERT INTO t2 SELECT x, x*x FROM t1; } expr {[file size test.db]>1024*12} } {1} integrity_check corrupt8-1.2 # Loop through each ptrmap entry. Corrupt the entry and make sure the # corruption is detected by the integrity_check. # for {set i 1024} {$i<2048} {incr i 5} { set oldval [hexio_read test.db $i 1] if {$oldval==0} break hexio_write test.db $i 00 do_test corrupt8-2.$i.0 { db close sqlite3 db test.db set x [db eval {PRAGMA integrity_check}] expr {$x!="ok"} } {1} for {set k 1} {$k<=5} {incr k} { if {$k==$oldval} continue hexio_write test.db $i 0$k do_test corrupt8-2.$i.$k { db close sqlite3 db test.db set x [db eval {PRAGMA integrity_check}] expr {$x!="ok"} } {1} } hexio_write test.db $i 06 do_test corrupt8-2.$i.6 { db close sqlite3 db test.db set x [db eval {PRAGMA integrity_check}] expr {$x!="ok"} } {1} hexio_write test.db $i $oldval if {$oldval>2} { set i2 [expr {$i+1+$i%4}] set oldval [hexio_read test.db $i2 1] hexio_write test.db $i2 [format %02x [expr {($oldval+1)&0xff}]] do_test corrupt8-2.$i.7 { db close sqlite3 db test.db set x [db eval {PRAGMA integrity_check}] expr {$x!="ok"} } {1} hexio_write test.db $i2 $oldval } } finish_test |