/ Check-in [cbf44ed9]
Login

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

Overview
Comment:Require exclusive access to the db to wrap the wal file. Have "PRAGMA wal_checkpoint = restart" block for this.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | server-edition
Files: files | file ages | folders
SHA3-256: cbf44ed9758d577e1450b53e645b73c9ca1ee29d2354ce6375c234a41a063400
User & Date: dan 2017-05-12 18:52:27
Context
2017-05-13
19:07
Avoid running recovery while there is another read/write client. check-in: a38858a2 user: dan tags: server-edition
2017-05-12
18:52
Require exclusive access to the db to wrap the wal file. Have "PRAGMA wal_checkpoint = restart" block for this. check-in: cbf44ed9 user: dan tags: server-edition
2017-05-10
16:18
Fix a problem causing a lock to be held past the end of a transaction. Use a blocking lock to take the read-lock on page 1 taken by all transactions. check-in: 2584df3d user: dan tags: server-edition
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/wal.c.

  1905   1905             ** checkpointed and behave accordingly. This seems unsafe though,
  1906   1906             ** as it would leave the system in a state where the contents of
  1907   1907             ** the wal-index header do not match the contents of the 
  1908   1908             ** file-system. To avoid this, update the wal-index header to
  1909   1909             ** indicate that the log file contains zero valid frames.  */
  1910   1910             walRestartHdr(pWal, salt1);
  1911   1911             rc = sqlite3OsTruncate(pWal->pWalFd, 0);
         1912  +        }else if( walIsServer(pWal) ){
         1913  +          assert( eMode==SQLITE_CHECKPOINT_RESTART );
         1914  +          walRestartHdr(pWal, salt1);
  1912   1915           }
  1913   1916           walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
  1914   1917         }
  1915   1918       }
  1916   1919     }
  1917   1920   
  1918   1921    walcheckpoint_out:
................................................................................
  3122   3125     if( memcmp(&pWal->hdr, (void *)pLive, sizeof(WalIndexHdr))!=0 ){
  3123   3126       iFirst = pLive->mxFrame+1;
  3124   3127     }
  3125   3128   
  3126   3129     /* See if it is possible to write these frames into the start of the
  3127   3130     ** log file, instead of appending to it at pWal->hdr.mxFrame.
  3128   3131     */
  3129         -  if( SQLITE_OK!=(rc = walRestartLog(pWal)) ){
         3132  +  if( walIsServer(pWal)==0 && SQLITE_OK!=(rc = walRestartLog(pWal)) ){
  3130   3133       return rc;
  3131   3134     }
  3132   3135   
  3133   3136     /* If this is the first frame written into the log, write the WAL
  3134   3137     ** header to the start of the WAL file. See comments at the top of
  3135   3138     ** this source file for a description of the WAL header format.
  3136   3139     */
................................................................................
  3375   3378     ** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
  3376   3379     ** immediately, and a busy-handler is configured, it is invoked and the
  3377   3380     ** writer lock retried until either the busy-handler returns 0 or the
  3378   3381     ** lock is successfully obtained.
  3379   3382     */
  3380   3383     if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
  3381   3384       if( walIsServer(pWal) ){
  3382         -      rc = sqlite3ServerLock(pWal->pServer, 0, 1, 1);
         3385  +      if( eMode>=SQLITE_CHECKPOINT_RESTART ){
         3386  +        /* Exclusive lock on page 1. This is exclusive access to the db. */
         3387  +        rc = sqlite3ServerLock(pWal->pServer, 1, 1, 1);
         3388  +      }else{
         3389  +        /* Take the server write-lock ("page" 0) */
         3390  +        rc = sqlite3ServerLock(pWal->pServer, 0, 1, 1);
         3391  +      }
  3383   3392       }else{
  3384   3393         rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
  3385   3394       }
  3386   3395       if( rc==SQLITE_OK ){
  3387   3396         pWal->writeLock = 1;
  3388   3397       }else if( rc==SQLITE_BUSY ){
  3389   3398         eMode2 = SQLITE_CHECKPOINT_PASSIVE;
................................................................................
  3427   3436     }
  3428   3437   
  3429   3438     /* Release the locks. */
  3430   3439     sqlite3WalEndWriteTransaction(pWal);
  3431   3440     walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
  3432   3441     pWal->ckptLock = 0;
  3433   3442     WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
         3443  +  if( walIsServer(pWal) ) sqlite3ServerEnd(pWal->pServer);
  3434   3444     return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
  3435   3445   }
  3436   3446   
  3437   3447   /* Return the value to pass to a sqlite3_wal_hook callback, the
  3438   3448   ** number of frames in the WAL at the point of the last commit since
  3439   3449   ** sqlite3WalCallback() was called.  If no commits have occurred since
  3440   3450   ** the last call, then return 0.

Changes to test/serverwal.test.

    57     57     } db2
    58     58   } {}
    59     59   do_test 2.2 {
    60     60     execsql COMMIT db
    61     61     execsql COMMIT db2
    62     62   } {}
    63     63   db close
           64  +db2 close
    64     65   
    65     66   #-------------------------------------------------------------------------
    66     67   # That the wal file can be wrapped around.
    67     68   #
    68     69   reset_db
    69     70   do_execsql_test 3.0 {
    70     71     PRAGMA journal_mode = wal;
................................................................................
    75     76     INSERT INTO ttt VALUES(7, 8);
    76     77     INSERT INTO ttt VALUES(9, 10);
    77     78   } {wal}
    78     79   
    79     80   do_test 3.1 {
    80     81     set N [file size test.db-wal]
    81     82     execsql {
    82         -    PRAGMA wal_checkpoint;
           83  +    PRAGMA wal_checkpoint = restart;
    83     84       INSERT INTO ttt VALUES(11, 12);
    84     85       INSERT INTO ttt VALUES(13, 14);
    85     86     }
    86     87     expr {$N == [file size test.db-wal]}
    87     88   } {1}
    88     89   
    89     90   #-------------------------------------------------------------------------
................................................................................
   105    106     PRAGMA integrity_check;
   106    107     BEGIN;
   107    108       UPDATE ttt SET b=a;
   108    109     ROLLBACK;
   109    110     PRAGMA integrity_check;
   110    111   } {ok ok}
   111    112   
          113  +reset_db
          114  +do_execsql_test 5.1 {
          115  +  CREATE TABLE xyz(a);
          116  +  PRAGMA journal_mode = wal;
          117  +  INSERT INTO xyz VALUES(1);
          118  +  INSERT INTO xyz VALUES(2);
          119  +  INSERT INTO xyz VALUES(3);
          120  +} {wal}
          121  +
          122  +breakpoint
          123  +
          124  +do_test 5.2 {
          125  +  sqlite3 db2 test.db
          126  +  execsql { SELECT * FROM xyz } db2
          127  +} {1 2 3}
          128  +
          129  +do_execsql_test 5.3 {
          130  +  PRAGMA wal_checkpoint = restart 
          131  +} {0 0 0}
          132  +
          133  +do_test 5.4 {
          134  +  execsql { SELECT * FROM xyz } db2
          135  +} {1 2 3}
          136  +
   112    137   finish_test
   113    138