File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / sqlite3 / test / backup_ioerr.test
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:04:16 2012 UTC (12 years, 10 months ago) by misho
Branches: sqlite3, MAIN
CVS tags: v3_7_10, HEAD
sqlite3

    1: # 2009 January 30
    2: #
    3: # The author disclaims copyright to this source code.  In place of
    4: # a legal notice, here is a blessing:
    5: #
    6: #    May you do good and not evil.
    7: #    May you find forgiveness for yourself and forgive others.
    8: #    May you share freely, never taking more than you give.
    9: #
   10: #***********************************************************************
   11: # This file implements regression tests for SQLite library.  The
   12: # focus of this file is testing the handling of IO errors by the
   13: # sqlite3_backup_XXX APIs.
   14: #
   15: # $Id: backup_ioerr.test,v 1.1.1.1 2012/02/21 17:04:16 misho Exp $
   16: 
   17: set testdir [file dirname $argv0]
   18: source $testdir/tester.tcl
   19: 
   20: proc data_checksum {db file} { 
   21:   $db one "SELECT md5sum(a, b) FROM ${file}.t1" 
   22: }
   23: proc test_contents {name db1 file1 db2 file2} {
   24:   $db2 eval {select * from sqlite_master}
   25:   $db1 eval {select * from sqlite_master}
   26:   set checksum [data_checksum $db2 $file2]
   27:   uplevel [list do_test $name [list data_checksum $db1 $file1] $checksum]
   28: }
   29: 
   30: #--------------------------------------------------------------------
   31: # This proc creates a database of approximately 290 pages. Depending
   32: # on whether or not auto-vacuum is configured. Test cases backup_ioerr-1.*
   33: # verify nothing more than this assumption.
   34: #
   35: proc populate_database {db {xtra_large 0}} {
   36:   execsql {
   37:     BEGIN;
   38:     CREATE TABLE t1(a, b);
   39:     INSERT INTO t1 VALUES(1, randstr(1000,1000));
   40:     INSERT INTO t1 SELECT a+ 1, randstr(1000,1000) FROM t1;
   41:     INSERT INTO t1 SELECT a+ 2, randstr(1000,1000) FROM t1;
   42:     INSERT INTO t1 SELECT a+ 4, randstr(1000,1000) FROM t1;
   43:     INSERT INTO t1 SELECT a+ 8, randstr(1000,1000) FROM t1;
   44:     INSERT INTO t1 SELECT a+16, randstr(1000,1000) FROM t1;
   45:     INSERT INTO t1 SELECT a+32, randstr(1000,1000) FROM t1;
   46:     CREATE INDEX i1 ON t1(b);
   47:     COMMIT;
   48:   } $db
   49:   if {$xtra_large} {
   50:     execsql { INSERT INTO t1 SELECT a+64, randstr(1000,1000) FROM t1 } $db
   51:   }
   52: }
   53: do_test backup_ioerr-1.1 {
   54:   populate_database db
   55:   set nPage [expr {[file size test.db] / 1024}]
   56:   expr {$nPage>130 && $nPage<160}
   57: } {1}
   58: do_test backup_ioerr-1.2 {
   59:   expr {[file size test.db] > $sqlite_pending_byte}
   60: } {1}
   61: do_test backup_ioerr-1.3 {
   62:   db close
   63:   forcedelete test.db
   64: } {}
   65: 
   66: # Turn off IO error simulation.
   67: #
   68: proc clear_ioerr_simulation {} {
   69:   set ::sqlite_io_error_hit 0
   70:   set ::sqlite_io_error_hardhit 0
   71:   set ::sqlite_io_error_pending 0
   72:   set ::sqlite_io_error_persist 0
   73: }
   74: 
   75: #--------------------------------------------------------------------
   76: # The following procedure runs with SQLite's IO error simulation 
   77: # enabled.
   78: #
   79: #   1) Start with a reasonably sized database. One that includes the
   80: #      pending-byte (locking) page.
   81: #
   82: #   2) Open a backup process. Set the cache-size for the destination
   83: #      database to 10 pages only.
   84: #
   85: #   3) Step the backup process N times to partially backup the database
   86: #      file. If an IO error is reported, then the backup process is
   87: #      concluded with a call to backup_finish().
   88: #
   89: #      If an IO error occurs, verify that:
   90: #
   91: #      * the call to backup_step() returns an SQLITE_IOERR_XXX error code.
   92: #
   93: #      * after the failed call to backup_step() but before the call to
   94: #        backup_finish() the destination database handle error code and 
   95: #        error message remain unchanged.
   96: #
   97: #      * the call to backup_finish() returns an SQLITE_IOERR_XXX error code.
   98: #
   99: #      * following the call to backup_finish(), the destination database
  100: #        handle has been populated with an error code and error message.
  101: #
  102: #   4) Write to the database via the source database connection. Check 
  103: #      that:
  104: #
  105: #      * If an IO error occurs while writing the source database, the
  106: #        write operation should report an IO error. The backup should 
  107: #        proceed as normal.
  108: #
  109: #      * If an IO error occurs while updating the backup, the write 
  110: #        operation should proceed normally. The error should be reported
  111: #        from the next call to backup_step() (in step 5 of this test
  112: #        procedure).
  113: #
  114: #   5) Step the backup process to finish the backup. If an IO error is 
  115: #      reported, then the backup process is concluded with a call to 
  116: #      backup_finish().
  117: #
  118: #      Test that if an IO error occurs, or if one occured while updating
  119: #      the backup database during step 4, then the conditions listed
  120: #      under step 3 are all true.
  121: #
  122: #   6) Finish the backup process.
  123: #
  124: #   * If the backup succeeds (backup_finish() returns SQLITE_OK), then
  125: #     the contents of the backup database should match that of the
  126: #     source database.
  127: #
  128: #   * If the backup fails (backup_finish() returns other than SQLITE_OK), 
  129: #     then the contents of the backup database should be as they were 
  130: #     before the operation was started.
  131: #
  132: # The following factors are varied:
  133: #
  134: #   * Destination database is initially larger than the source database, OR
  135: #   * Destination database is initially smaller than the source database.
  136: #
  137: #   * IO errors are transient, OR
  138: #   * IO errors are persistent.
  139: #
  140: #   * Destination page-size is smaller than the source.
  141: #   * Destination page-size is the same as the source.
  142: #   * Destination page-size is larger than the source.
  143: #
  144: 
  145: set iTest 1
  146: foreach bPersist {0 1} {
  147: foreach iDestPagesize {512 1024 4096} {
  148: foreach zSetupBak [list "" {populate_database ddb 1}] {
  149: 
  150:   incr iTest
  151:   set bStop 0
  152: for {set iError 1} {$bStop == 0} {incr iError} {
  153:   # Disable IO error simulation.
  154:   clear_ioerr_simulation
  155: 
  156:   catch { ddb close }
  157:   catch { sdb close }
  158:   catch { forcedelete test.db }
  159:   catch { forcedelete bak.db }
  160: 
  161:   # Open the source and destination databases.
  162:   sqlite3 sdb test.db
  163:   sqlite3 ddb bak.db
  164: 
  165:   # Step 1: Populate the source and destination databases.
  166:   populate_database sdb
  167:   ddb eval "PRAGMA page_size = $iDestPagesize"
  168:   ddb eval "PRAGMA cache_size = 10"
  169:   eval $zSetupBak
  170: 
  171:   # Step 2: Open the backup process.
  172:   sqlite3_backup B ddb main sdb main
  173: 
  174:   # Enable IO error simulation.
  175:   set ::sqlite_io_error_pending $iError
  176:   set ::sqlite_io_error_persist $bPersist
  177: 
  178:   # Step 3: Partially backup the database. If an IO error occurs, check
  179:   # a few things then skip to the next iteration of the loop.
  180:   #
  181:   set rc [B step 100]
  182:   if {$::sqlite_io_error_hardhit} {
  183: 
  184:     do_test backup_ioerr-$iTest.$iError.1 {
  185:       string match SQLITE_IOERR* $rc
  186:     } {1}
  187:     do_test backup_ioerr-$iTest.$iError.2 {
  188:       list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
  189:     } {SQLITE_OK {not an error}}
  190: 
  191:     set rc [B finish]
  192:     do_test backup_ioerr-$iTest.$iError.3 {
  193:       string match SQLITE_IOERR* $rc
  194:     } {1}
  195: 
  196:     do_test backup_ioerr-$iTest.$iError.4 {
  197:       sqlite3_errmsg ddb
  198:     } {disk I/O error}
  199: 
  200:     clear_ioerr_simulation
  201:     sqlite3 ddb bak.db
  202:     integrity_check backup_ioerr-$iTest.$iError.5 ddb
  203: 
  204:     continue
  205:   }
  206: 
  207:   # No IO error was encountered during step 3. Check that backup_step()
  208:   # returned SQLITE_OK before proceding.
  209:   do_test backup_ioerr-$iTest.$iError.6 {
  210:     expr {$rc eq "SQLITE_OK"}
  211:   } {1}
  212: 
  213:   # Step 4: Write to the source database.
  214:   set rc [catchsql { UPDATE t1 SET b = randstr(1000,1000) WHERE a < 50 } sdb]
  215: 
  216:   if {[lindex $rc 0] && $::sqlite_io_error_persist==0} {
  217:     # The IO error occured while updating the source database. In this
  218:     # case the backup should be able to continue.
  219:     set rc [B step 5000]
  220:     if { $rc != "SQLITE_IOERR_UNLOCK" } {
  221:       do_test backup_ioerr-$iTest.$iError.7 {
  222:         list [B step 5000] [B finish]
  223:       } {SQLITE_DONE SQLITE_OK}
  224: 
  225:       clear_ioerr_simulation
  226:       test_contents backup_ioerr-$iTest.$iError.8 ddb main sdb main
  227:       integrity_check backup_ioerr-$iTest.$iError.9 ddb
  228:     } else {
  229:       do_test backup_ioerr-$iTest.$iError.10 {
  230:         B finish
  231:       } {SQLITE_IOERR_UNLOCK}
  232:     }
  233: 
  234:     clear_ioerr_simulation
  235:     sqlite3 ddb bak.db
  236:     integrity_check backup_ioerr-$iTest.$iError.11 ddb
  237: 
  238:     continue
  239:   }
  240: 
  241:   # Step 5: Finish the backup operation. If an IO error occurs, check that
  242:   # it is reported correctly and skip to the next iteration of the loop.
  243:   #
  244:   set rc [B step 5000]
  245:   if {$rc != "SQLITE_DONE"} {
  246:     do_test backup_ioerr-$iTest.$iError.12 {
  247:       string match SQLITE_IOERR* $rc
  248:     } {1}
  249:     do_test backup_ioerr-$iTest.$iError.13 {
  250:       list [sqlite3_errcode ddb] [sqlite3_errmsg ddb]
  251:     } {SQLITE_OK {not an error}}
  252: 
  253:     set rc [B finish]
  254:     do_test backup_ioerr-$iTest.$iError.14 {
  255:       string match SQLITE_IOERR* $rc
  256:     } {1}
  257:     do_test backup_ioerr-$iTest.$iError.15 {
  258:       sqlite3_errmsg ddb
  259:     } {disk I/O error}
  260: 
  261:     clear_ioerr_simulation
  262:     sqlite3 ddb bak.db
  263:     integrity_check backup_ioerr-$iTest.$iError.16 ddb
  264: 
  265:     continue
  266:   }
  267: 
  268:   # The backup was successfully completed.
  269:   #
  270:   do_test backup_ioerr-$iTest.$iError.17 {
  271:     list [set rc] [B finish]
  272:   } {SQLITE_DONE SQLITE_OK}
  273: 
  274:   clear_ioerr_simulation
  275:   sqlite3 sdb test.db
  276:   sqlite3 ddb bak.db
  277: 
  278:   test_contents backup_ioerr-$iTest.$iError.18 ddb main sdb main
  279:   integrity_check backup_ioerr-$iTest.$iError.19 ddb
  280: 
  281:   set bStop [expr $::sqlite_io_error_pending<=0]
  282: }}}}
  283: 
  284: catch { sdb close }
  285: catch { ddb close }
  286: finish_test

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>