/ Check-in [491f8f96]
Login

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

Overview
Comment:Coverage testing for balance_quick() and balance_deeper(). (CVS 5382)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 491f8f9613d2b886acad2ab8f631a4ec61ad698d
User & Date: danielk1977 2008-07-09 11:49:47
Context
2008-07-09
13:28
Begin adding the failsafe() macro. (CVS 5383) check-in: 8aae4fe7 user: drh tags: trunk
11:49
Coverage testing for balance_quick() and balance_deeper(). (CVS 5382) check-in: 491f8f96 user: danielk1977 tags: trunk
01:39
Additional test coverage in select.c and expr.c. (CVS 5381) check-in: c6cf0847 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/btree.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** $Id: btree.c,v 1.473 2008/07/08 19:34:07 drh Exp $
           12  +** $Id: btree.c,v 1.474 2008/07/09 11:49:47 danielk1977 Exp $
    13     13   **
    14     14   ** This file implements a external (disk-based) database using BTrees.
    15     15   ** See the header comment on "btreeInt.h" for additional information.
    16     16   ** Including a description of file format and an overview of operation.
    17     17   */
    18     18   #include "btreeInt.h"
    19     19   
................................................................................
   663    663   
   664    664   /*
   665    665   ** Defragment the page given.  All Cells are moved to the
   666    666   ** end of the page and all free space is collected into one
   667    667   ** big FreeBlk that occurs in between the header and cell
   668    668   ** pointer array and the cell content area.
   669    669   */
   670         -static int defragmentPage(MemPage *pPage){
          670  +static void defragmentPage(MemPage *pPage){
   671    671     int i;                     /* Loop counter */
   672    672     int pc;                    /* Address of a i-th cell */
   673    673     int addr;                  /* Offset of first byte after cell pointer array */
   674    674     int hdr;                   /* Offset to the page header */
   675    675     int size;                  /* Size of a cell */
   676    676     int usableSize;            /* Number of usable bytes on a page */
   677    677     int cellOffset;            /* Offset to the cell pointer array */
................................................................................
   708    708     assert( brk>=cellOffset+2*nCell );
   709    709     put2byte(&data[hdr+5], brk);
   710    710     data[hdr+1] = 0;
   711    711     data[hdr+2] = 0;
   712    712     data[hdr+7] = 0;
   713    713     addr = cellOffset+2*nCell;
   714    714     memset(&data[addr], 0, brk-addr);
   715         -  return SQLITE_OK;
   716    715   }
   717    716   
   718    717   /*
   719    718   ** Allocate nByte bytes of space on a page.
   720    719   **
   721    720   ** Return the index into pPage->aData[] of the first byte of
   722    721   ** the new allocation. Or return 0 if there is not enough free
................................................................................
   769    768     /* Allocate memory from the gap in between the cell pointer array
   770    769     ** and the cell content area.
   771    770     */
   772    771     top = get2byte(&data[hdr+5]);
   773    772     nCell = get2byte(&data[hdr+3]);
   774    773     cellOffset = pPage->cellOffset;
   775    774     if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){
   776         -    if( defragmentPage(pPage) ) return 0;
          775  +    defragmentPage(pPage);
   777    776       top = get2byte(&data[hdr+5]);
   778    777     }
   779    778     top -= nByte;
   780    779     assert( cellOffset + 2*nCell <= top );
   781    780     put2byte(&data[hdr+5], top);
   782    781     return top;
   783    782   }
................................................................................
  4641   4640       data = pPage->aData;
  4642   4641       hdr = pPage->hdrOffset;
  4643   4642       top = get2byte(&data[hdr+5]);
  4644   4643       cellOffset = pPage->cellOffset;
  4645   4644       end = cellOffset + 2*pPage->nCell + 2;
  4646   4645       ins = cellOffset + 2*i;
  4647   4646       if( end > top - sz ){
  4648         -      rc = defragmentPage(pPage);
  4649         -      if( rc!=SQLITE_OK ) return rc;
         4647  +      defragmentPage(pPage);
  4650   4648         top = get2byte(&data[hdr+5]);
  4651   4649         assert( end + sz <= top );
  4652   4650       }
  4653   4651       idx = allocateSpace(pPage, sz);
  4654   4652       assert( idx>0 );
  4655   4653       assert( end <= get2byte(&data[hdr+5]) );
  4656   4654       pPage->nCell++;
................................................................................
  4794   4792     /* Set the parent of the newly allocated page to pParent. */
  4795   4793     pNew->pParent = pParent;
  4796   4794     sqlite3PagerRef(pParent->pDbPage);
  4797   4795   
  4798   4796     /* pPage is currently the right-child of pParent. Change this
  4799   4797     ** so that the right-child is the new page allocated above and
  4800   4798     ** pPage is the next-to-right child. 
         4799  +  **
         4800  +  ** Ignore the return value of the call to fillInCell(). fillInCell()
         4801  +  ** may only return other than SQLITE_OK if it is required to allocate
         4802  +  ** one or more overflow pages. Since an internal table B-Tree cell 
         4803  +  ** may never spill over onto an overflow page (it is a maximum of 
         4804  +  ** 13 bytes in size), it is not neccessary to check the return code.
         4805  +  **
         4806  +  ** Similarly, the insertCell() function cannot fail if the page
         4807  +  ** being inserted into is already writable and the cell does not 
         4808  +  ** contain an overflow pointer. So ignore this return code too.
  4801   4809     */
  4802   4810     assert( pPage->nCell>0 );
  4803   4811     pCell = findCell(pPage, pPage->nCell-1);
  4804   4812     sqlite3BtreeParseCellPtr(pPage, pCell, &info);
  4805         -  rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
  4806         -  if( rc!=SQLITE_OK ){
  4807         -    return rc;
  4808         -  }
         4813  +  fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize);
  4809   4814     assert( parentSize<64 );
  4810         -  rc = insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4);
  4811         -  if( rc!=SQLITE_OK ){
  4812         -    return rc;
  4813         -  }
         4815  +  assert( sqlite3PagerIswriteable(pParent->pDbPage) );
         4816  +  insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4);
  4814   4817     put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno);
  4815   4818     put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew);
  4816   4819   
  4817   4820   #ifndef SQLITE_OMIT_AUTOVACUUM
  4818   4821     /* If this is an auto-vacuum database, update the pointer map
  4819   4822     ** with entries for the new page, and any pointer from the 
  4820   4823     ** cell on the page to an overflow page.
................................................................................
  4914   4917     assert( sqlite3PagerIswriteable(pPage->pDbPage) || pPage->nOverflow==1 );
  4915   4918     pBt = pPage->pBt;
  4916   4919     pParent = pPage->pParent;
  4917   4920     assert( pParent );
  4918   4921     if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){
  4919   4922       return rc;
  4920   4923     }
         4924  +
  4921   4925     TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
  4922   4926   
  4923   4927   #ifndef SQLITE_OMIT_QUICKBALANCE
  4924   4928     /*
  4925   4929     ** A special case:  If a new entry has just been inserted into a
  4926   4930     ** table (that is, a btree with integer keys and all data at the leaves)
  4927   4931     ** and the new entry is the right-most entry in the tree (it has the
................................................................................
  5595   5599     if( pBt->autoVacuum ){
  5596   5600       int i;
  5597   5601       rc = ptrmapPut(pBt, pChild->pgno, PTRMAP_BTREE, pPage->pgno);
  5598   5602       if( rc ) goto balancedeeper_out;
  5599   5603       for(i=0; i<pChild->nCell; i++){
  5600   5604         rc = ptrmapPutOvfl(pChild, i);
  5601   5605         if( rc!=SQLITE_OK ){
  5602         -        return rc;
         5606  +        goto balancedeeper_out;
  5603   5607         }
  5604   5608       }
  5605   5609     }
  5606   5610   #endif
  5607   5611     rc = balance_nonroot(pChild);
  5608   5612   
  5609   5613   balancedeeper_out:

Changes to test/ioerr.test.

    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing for correct handling of I/O errors
    13     13   # such as writes failing because the disk is full.
    14     14   # 
    15     15   # The tests in this file use special facilities that are only
    16     16   # available in the SQLite test fixture.
    17     17   #
    18         -# $Id: ioerr.test,v 1.39 2008/07/08 17:13:59 danielk1977 Exp $
           18  +# $Id: ioerr.test,v 1.40 2008/07/09 11:49:48 danielk1977 Exp $
    19     19   
    20     20   set testdir [file dirname $argv0]
    21     21   source $testdir/tester.tcl
    22     22   
    23     23   # If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error
    24     24   # on the 8th IO operation in the SQL script below doesn't report an error.
    25     25   #
................................................................................
   324    324     db eval { PRAGMA page_size = 1024 }
   325    325     db eval { CREATE TABLE t1(x) }
   326    326     db eval { INSERT INTO t1 VALUES(randomblob(1100)); }
   327    327   } -tclbody {
   328    328     db eval { INSERT INTO t1 VALUES(randomblob(2000)); }
   329    329   }
   330    330   sqlite3_simulate_device -char {} -sectorsize 0
          331  +catch {db close}
          332  +
          333  +do_ioerr_test ioerr-13 -ckrefcount true -erc 1 -sqlprep {
          334  +  PRAGMA auto_vacuum = incremental;
          335  +  CREATE TABLE t1(x);
          336  +  CREATE TABLE t2(x);
          337  +  INSERT INTO t2 VALUES(randomblob(1500));
          338  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          339  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          340  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          341  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          342  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          343  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          344  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          345  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          346  +  INSERT INTO t1 VALUES(randomblob(20));
          347  +  INSERT INTO t1 SELECT x FROM t1;
          348  +  INSERT INTO t1 SELECT x FROM t1;
          349  +  INSERT INTO t1 SELECT x FROM t1;
          350  +  INSERT INTO t1 SELECT x FROM t1;
          351  +  INSERT INTO t1 SELECT x FROM t1;
          352  +  INSERT INTO t1 SELECT x FROM t1;             /* 64 entries in t1 */
          353  +  INSERT INTO t1 SELECT x FROM t1 LIMIT 14;    /* 78 entries in t1 */
          354  +  DELETE FROM t2 WHERE rowid = 3;
          355  +} -sqlbody {
          356  +  -- This statement uses the balance_quick() optimization. The new page
          357  +  -- is appended to the database file. But the overflow page used by
          358  +  -- the new record will be positioned near the start of the database
          359  +  -- file, in the gap left by the "DELETE FROM t2 WHERE rowid=3" statement
          360  +  -- above.
          361  +  --
          362  +  -- The point of this is that the statement wil need to update two pointer
          363  +  -- map pages. Which introduces another opportunity for an IO error.
          364  +  --
          365  +  INSERT INTO t1 VALUES(randomblob(2000));
          366  +}
          367  +
          368  +do_ioerr_test ioerr-14 -ckrefcount true -erc 1 -sqlprep {
          369  +  PRAGMA auto_vacuum = incremental;
          370  +  CREATE TABLE t1(x);
          371  +  CREATE TABLE t2(x);
          372  +  INSERT INTO t2 VALUES(randomblob(1500));
          373  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          374  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          375  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          376  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          377  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          378  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          379  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          380  +  INSERT INTO t2 SELECT randomblob(1500) FROM t2;
          381  +
          382  +  -- This statement inserts a row into t1 with an overflow page at the
          383  +  -- end of the file. A long way from its parent (the root of t1).
          384  +  INSERT INTO t1 VALUES(randomblob(1500));
          385  +  DELETE FROM t2 WHERE rowid<10;
          386  +} -sqlbody {
          387  +  -- This transaction will cause the root-page of table t1 to divide
          388  +  -- (by calling balance_deeper()). When it does, the "parent" page of the
          389  +  -- overflow page inserted in the -sqlprep block above will change and
          390  +  -- the corresponding pointer map page be updated. This test case attempts
          391  +  -- to cause an IO error during the pointer map page update.
          392  +  --
          393  +  BEGIN;
          394  +  INSERT INTO t1 VALUES(randomblob(100));
          395  +  INSERT INTO t1 VALUES(randomblob(100));
          396  +  INSERT INTO t1 VALUES(randomblob(100));
          397  +  INSERT INTO t1 VALUES(randomblob(100));
          398  +  INSERT INTO t1 VALUES(randomblob(100));
          399  +  INSERT INTO t1 VALUES(randomblob(100));
          400  +  INSERT INTO t1 VALUES(randomblob(100));
          401  +  INSERT INTO t1 VALUES(randomblob(100));
          402  +  INSERT INTO t1 VALUES(randomblob(100));
          403  +  INSERT INTO t1 VALUES(randomblob(100));
          404  +  COMMIT;
          405  +}
   331    406   
   332    407   finish_test
   333    408