/ Check-in [4012bb3a]
Login

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

Overview
Comment:Fix another RBU case similar to the previous. This one for systems where the sector-size is larger than the page-size.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:4012bb3aa91927156ba149caa4e5c622b0729d79
User & Date: dan 2017-03-02 16:56:48
References
2017-03-07
14:46
Fix another RBU case similar to the previous. This one for systems where the sector-size is larger than the page-size. Cherrypick of [4012bb3a]. check-in: 59a11b7f user: dan tags: version-3.17.0-rbu-fixes
Context
2017-03-07
14:46
Fix another RBU case similar to the previous. This one for systems where the sector-size is larger than the page-size. Cherrypick of [4012bb3a]. check-in: 59a11b7f user: dan tags: version-3.17.0-rbu-fixes
2017-03-02
23:40
Fix a bug in the 'start of ...' date/time modifiers when they follow a julian day number. Fix for ticket [6097cb92745327a1]. check-in: 081dbcfb user: drh tags: trunk
16:56
Fix another RBU case similar to the previous. This one for systems where the sector-size is larger than the page-size. check-in: 4012bb3a user: dan tags: trunk
14:51
When saving the state of an RBU update in the incremental-checkpoint phase, sync the database file. Otherwise, if a power failure occurs and the RBU update resumed following system recovery, the database may become corrupt. check-in: edee6a80 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/rbu/rbucrash2.test.

    41     41     INSERT INTO data_t1 VALUES('five', randomblob(3500), NULL, 0);
    42     42     INSERT INTO data_t1 VALUES('six', randomblob(3500), NULL, 0);
    43     43   }
    44     44   db_save_and_close
    45     45   
    46     46   proc do_rbu_crash_test2 {tn script} {
    47     47   
    48         -  foreach f {test.db test.db2} {
           48  +  foreach {f blksz} {
           49  +    test.db   512
           50  +    test.db2  512
           51  +    test.db   4096
           52  +    test.db2  4096
           53  +  } {
    49     54       set bDone 0
    50     55       for {set iDelay 1} {$bDone==0} {incr iDelay} {
    51     56         forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
    52     57         db_restore
    53     58     
    54     59         set res [
    55     60           crashsql -file $f -delay $iDelay -tclbody $script -dflt 1 -opendb {} \
    56         -            -blocksize 512 {}
           61  +            -blocksize $blksz {}
    57     62         ]
    58     63     
    59     64         set bDone 1
    60     65         if {$res == "1 {child process exited abnormally}"} {
    61     66           set bDone 0
    62     67         } elseif {$res != "0 {}"} {
    63     68           error "unexected catchsql result: $res"
................................................................................
    64     69         }
    65     70     
    66     71         sqlite3rbu rbu test.db test.db2
    67     72         while {[rbu step]=="SQLITE_OK"} {}
    68     73         rbu close
    69     74     
    70     75         sqlite3 db test.db
    71         -      do_execsql_test $tn.delay=$iDelay.f=$f {
           76  +      do_execsql_test $tn.delay=$iDelay.f=$f.blksz=$blksz {
    72     77           PRAGMA integrity_check;
    73     78         } {ok}
    74     79         db close
    75     80       }
    76     81     }
    77     82   }
    78     83   

Changes to ext/rbu/rbuprogress.test.

    36     36       INSERT INTO rbu_count VALUES('data_t1', 3);
    37     37     }
    38     38     return $filename
    39     39   }
    40     40   
    41     41   
    42     42   do_execsql_test 1.0 {
           43  +  PRAGMA page_size = 4096;
    43     44     CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
    44     45   }
    45     46   
    46     47   do_test 1.1 {
    47     48     create_rbu1 rbu.db
    48     49     sqlite3rbu rbu test.db rbu.db
    49     50     rbu bp_progress
................................................................................
   262    263     }] {SQLITE_DONE}]
   263    264   }
   264    265   
   265    266   foreach bReopen {0 1} {
   266    267     do_test 3.$bReopen.1.0 {
   267    268       reset_db
   268    269       execsql {
          270  +      PRAGMA page_size = 4096;
   269    271         CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
   270    272         CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
   271    273         CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
   272    274         CREATE TABLE t4(a INTEGER PRIMARY KEY, b);
   273    275       }
   274    276       create_db_file rbu.db {
   275    277         CREATE TABLE data_t1(a, b, rbu_control);

Changes to ext/rbu/sqlite3rbu.c.

   352    352     int rc;                         /* Value returned by last rbu_step() call */
   353    353     char *zErrmsg;                  /* Error message if rc!=SQLITE_OK */
   354    354     int nStep;                      /* Rows processed for current object */
   355    355     int nProgress;                  /* Rows processed for all objects */
   356    356     RbuObjIter objiter;             /* Iterator for skipping through tbl/idx */
   357    357     const char *zVfsName;           /* Name of automatically created rbu vfs */
   358    358     rbu_file *pTargetFd;            /* File handle open on target db */
          359  +  int nPagePerSector;             /* Pages per sector for pTargetFd */
   359    360     i64 iOalSz;
   360    361     i64 nPhaseOneStep;
   361    362   
   362    363     /* The following state variables are used as part of the incremental
   363    364     ** checkpoint stage (eStage==RBU_STAGE_CKPT). See comments surrounding
   364    365     ** function rbuSetupCheckpoint() for details.  */
   365    366     u32 iMaxFrame;                  /* Largest iWalFrame value in aFrame[] */
................................................................................
  2616   2617       p->iWalCksum = rbuShmChecksum(p);
  2617   2618     }
  2618   2619   
  2619   2620     if( p->rc==SQLITE_OK ){
  2620   2621       if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
  2621   2622         p->rc = SQLITE_DONE;
  2622   2623         p->eStage = RBU_STAGE_DONE;
         2624  +    }else{
         2625  +      int nSectorSize;
         2626  +      sqlite3_file *pDb = p->pTargetFd->pReal;
         2627  +      assert( p->nPagePerSector==0 );
         2628  +      nSectorSize = pDb->pMethods->xSectorSize(pDb);
         2629  +      if( nSectorSize>p->pgsz ){
         2630  +        p->nPagePerSector = nSectorSize / p->pgsz;
         2631  +      }else{
         2632  +        p->nPagePerSector = 1;
         2633  +      }
  2623   2634       }
  2624   2635     }
  2625   2636   }
  2626   2637   
  2627   2638   /*
  2628   2639   ** Called when iAmt bytes are read from offset iOff of the wal file while
  2629   2640   ** the rbu object is in capture mode. Record the frame number of the frame
................................................................................
  3271   3282               }
  3272   3283     
  3273   3284               if( p->rc==SQLITE_OK ){
  3274   3285                 p->eStage = RBU_STAGE_DONE;
  3275   3286                 p->rc = SQLITE_DONE;
  3276   3287               }
  3277   3288             }else{
  3278         -            RbuFrame *pFrame = &p->aFrame[p->nStep];
  3279         -            rbuCheckpointFrame(p, pFrame);
  3280         -            p->nStep++;
         3289  +            /* At one point the following block copied a single frame from the
         3290  +            ** wal file to the database file. So that one call to sqlite3rbu_step()
         3291  +            ** checkpointed a single frame. 
         3292  +            **
         3293  +            ** However, if the sector-size is larger than the page-size, and the
         3294  +            ** application calls sqlite3rbu_savestate() or close() immediately
         3295  +            ** after this step, then rbu_step() again, then a power failure occurs,
         3296  +            ** then the database page written here may be damaged. Work around
         3297  +            ** this by checkpointing frames until the next page in the aFrame[]
         3298  +            ** lies on a different disk sector to the current one. */
         3299  +            u32 iSector;
         3300  +            do{
         3301  +              RbuFrame *pFrame = &p->aFrame[p->nStep];
         3302  +              iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
         3303  +              rbuCheckpointFrame(p, pFrame);
         3304  +              p->nStep++;
         3305  +            }while( p->nStep<p->nFrame 
         3306  +                 && iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
         3307  +                 && p->rc==SQLITE_OK
         3308  +            );
  3281   3309             }
  3282   3310             p->nProgress++;
  3283   3311           }
  3284   3312           break;
  3285   3313         }
  3286   3314   
  3287   3315         default: