/ Check-in [71af9acb]
Login

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

Overview
Comment:Add further test cases for the new code on this branch. And a couple of fixes.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | readonly-wal-recovery
Files: files | file ages | folders
SHA3-256: 71af9acb227a91d9ad8798c9d0b12d6967e863d050f5cb1fddb45f25ee1f47db
User & Date: dan 2017-11-06 19:49:34
Context
2017-11-07
09:08
Add fault-injection tests for the code on this branch. check-in: a7d949fb user: dan tags: readonly-wal-recovery
2017-11-06
19:49
Add further test cases for the new code on this branch. And a couple of fixes. check-in: 71af9acb user: dan tags: readonly-wal-recovery
2017-11-04
21:06
Add further tests for the code added on this branch. check-in: a6716fcd user: dan tags: readonly-wal-recovery
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/wal.c.

  2195   2195     assert( pWal->nWiData>0 && pWal->apWiData[0] );
  2196   2196   
  2197   2197     /* Take WAL_READ_LOCK(0). This has the effect of preventing any
  2198   2198     ** live clients from running a checkpoint, but does not stop them
  2199   2199     ** from running recovery.  */
  2200   2200     rc = walLockShared(pWal, WAL_READ_LOCK(0));
  2201   2201     if( rc!=SQLITE_OK ){
  2202         -    return (rc==SQLITE_BUSY ? WAL_RETRY : rc);
         2202  +    if( rc==SQLITE_BUSY ) rc = WAL_RETRY;
         2203  +    goto begin_unlocked_out;
  2203   2204     }
  2204   2205     pWal->readLock = 0;
  2205   2206   
  2206   2207     /* Try to map the *-shm file again. If it succeeds this time, then 
  2207   2208     ** a non-readonly_shm connection has already connected to the database.
  2208   2209     ** In this case, start over with opening the transaction.
  2209   2210     ** 
................................................................................
  2219   2220       assert( rc!=SQLITE_OK );
  2220   2221       rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc);
  2221   2222       goto begin_unlocked_out;
  2222   2223     }
  2223   2224   
  2224   2225     memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
  2225   2226     rc = sqlite3OsFileSize(pWal->pWalFd, &szWal);
  2226         -  if( rc!=SQLITE_OK || (szWal<WAL_HDRSIZE && pWal->hdr.mxFrame==0) ){
         2227  +  if( rc!=SQLITE_OK ){
         2228  +    goto begin_unlocked_out;
         2229  +  }
         2230  +  if( szWal<WAL_HDRSIZE ){
  2227   2231       /* If the wal file is too small to contain a wal-header and the
  2228   2232       ** wal-index header has mxFrame==0, then it must be safe to proceed
  2229   2233       ** reading the database file only. However, the page cache cannot
  2230   2234       ** be trusted, as a read/write connection may have connected, written
  2231   2235       ** the db, run a checkpoint, truncated the wal file and disconnected
  2232   2236       ** since this client's last read transaction.  */
  2233   2237       *pChanged = 1;
         2238  +    rc = (pWal->hdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY);
  2234   2239       goto begin_unlocked_out;
  2235   2240     }
  2236   2241   
  2237   2242     /* Check the salt keys at the start of the wal file still match. */
  2238   2243     rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
  2239   2244     if( rc!=SQLITE_OK ){
  2240   2245       goto begin_unlocked_out;
................................................................................
  2264   2269         iOffset+=szFrame
  2265   2270     ){
  2266   2271       u32 pgno;                   /* Database page number for frame */
  2267   2272       u32 nTruncate;              /* dbsize field from frame header */
  2268   2273   
  2269   2274       /* Read and decode the next log frame. */
  2270   2275       rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
  2271         -    if( rc!=SQLITE_OK ){
  2272         -      if( rc==SQLITE_IOERR_SHORT_READ ){
  2273         -        /* If this branch is taken, some other client has truncated the
  2274         -        ** *-wal file since the call to sqlite3OsFileSize() above. This
  2275         -        ** indicates that a read-write client has connected to the system.
  2276         -        ** So retry opening this read transaction.  */
  2277         -        rc = WAL_RETRY;
  2278         -      }
  2279         -      break;
  2280         -    }
         2276  +    if( rc!=SQLITE_OK ) break;
  2281   2277       if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break;
  2282   2278   
  2283   2279       /* If nTruncate is non-zero, then a complete transaction has been
  2284   2280       ** appended to this wal file. Set rc to WAL_RETRY and break out of
  2285   2281       ** the loop.  */
  2286   2282       if( nTruncate ){
  2287   2283         rc = WAL_RETRY;

Changes to test/walro2.test.

   191    191       }
   192    192       code2 { db2 close }
   193    193       list [file size test.db-wal] [file size test.db-shm]
   194    194     } [list [wal_file_size 4 1024] 32768]
   195    195     do_test 3.3.3 {
   196    196       sql1 { SELECT * FROM t1 }
   197    197     } {i ii}
          198  +
          199  +  #-----------------------------------------------------------------------
          200  +  #
          201  +  #
          202  +  catch { code1 { db close } }
          203  +  catch { code2 { db2 close } }
          204  +  catch { code3 { db3 close } }
          205  +
          206  +  do_test 4.0 {
          207  +    code1 { forcedelete test.db }
          208  +    code1 { sqlite3 db test.db }
          209  +    sql1 {
          210  +      PRAGMA journal_mode = wal;
          211  +      CREATE TABLE t1(x);
          212  +      INSERT INTO t1 VALUES('hello');
          213  +      INSERT INTO t1 VALUES('world');
          214  +    }
          215  +
          216  +    forcecopy test.db test.db2
          217  +    forcecopy test.db-wal test.db2-wal
          218  +    forcecopy test.db-shm test.db2-shm
          219  +    
          220  +    code1 { db close }
          221  +  } {}
          222  +
          223  +  do_test 4.1.1 {
          224  +    code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
          225  +    sql2 { SELECT * FROM t1 }
          226  +  } {hello world}
          227  +
          228  +  do_test 4.1.2 {
          229  +    code3 { sqlite3 db3 test.db2 }
          230  +    sql3 {
          231  +      INSERT INTO t1 VALUES('!');
          232  +      PRAGMA wal_checkpoint = truncate;
          233  +    }
          234  +    code3 { db3 close }
          235  +  } {}
          236  +  do_test 4.1.3 {
          237  +    sql2 { SELECT * FROM t1 }
          238  +  } {hello world !}
          239  +
          240  +  catch { code1 { db close } }
          241  +  catch { code2 { db2 close } }
          242  +  catch { code3 { db3 close } }
          243  +
          244  +  do_test 4.2.1 {
          245  +    code1 { sqlite3 db test.db }
          246  +    sql1 {
          247  +      INSERT INTO t1 VALUES('!');
          248  +      INSERT INTO t1 VALUES('!');
          249  +
          250  +      PRAGMA cache_size = 10;
          251  +      CREATE TABLE t2(x);
          252  +
          253  +      BEGIN;
          254  +        WITH s(i) AS (
          255  +          SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500
          256  +          )
          257  +        INSERT INTO t2 SELECT randomblob(500) FROM s;
          258  +        SELECT count(*) FROM t2;
          259  +    } 
          260  +  } {500}
          261  +  do_test 4.2.2 {
          262  +    file size test.db-wal
          263  +  } {461152}
          264  +  do_test 4.2.4 {
          265  +    forcecopy test.db test.db2
          266  +    forcecopy test.db-wal test.db2-wal
          267  +    forcecopy test.db-shm test.db2-shm
          268  +
          269  +    code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
          270  +    sql2 {
          271  +      SELECT * FROM t1;
          272  +      SELECT count(*) FROM t2;
          273  +    }
          274  +  } {hello world ! ! 0}
          275  +
          276  +  #-----------------------------------------------------------------------
          277  +  #
          278  +  #
          279  +  catch { code1 { db close } }
          280  +  catch { code2 { db2 close } }
          281  +  catch { code3 { db3 close } }
          282  +
          283  +  do_test 5.0 {
          284  +    code1 { forcedelete test.db }
          285  +    code1 { sqlite3 db test.db }
          286  +    sql1 {
          287  +      PRAGMA journal_mode = wal;
          288  +      CREATE TABLE t1(x);
          289  +      INSERT INTO t1 VALUES('hello');
          290  +      INSERT INTO t1 VALUES('world');
          291  +      INSERT INTO t1 VALUES('!');
          292  +      INSERT INTO t1 VALUES('world');
          293  +      INSERT INTO t1 VALUES('hello');
          294  +    }
          295  +
          296  +    forcecopy test.db test.db2
          297  +    forcecopy test.db-wal test.db2-wal
          298  +    forcecopy test.db-shm test.db2-shm
          299  +    
          300  +    code1 { db close }
          301  +  } {}
          302  +
          303  +  do_test 5.1 {
          304  +    code2 { sqlite3 db2 file:test.db2?readonly_shm=1 }
          305  +    sql2 {
          306  +      SELECT * FROM t1;
          307  +    }
          308  +  } {hello world ! world hello}
          309  +
          310  +  do_test 5.2 {
          311  +    code1 {
          312  +      proc handle_read {op args} {
          313  +        if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
          314  +          set ::res2 [sql2 { SELECT * FROM t1 }]
          315  +        }
          316  +        puts "$msg xRead $args"
          317  +        return "SQLITE_OK"
          318  +      }
          319  +      testvfs tvfs -fullshm 1
          320  +
          321  +      sqlite3 db file:test.db2?vfs=tvfs
          322  +      db eval { SELECT * FROM sqlite_master }
          323  +
          324  +      tvfs filter xRead
          325  +      tvfs script handle_read
          326  +    }
          327  +    sql1 {
          328  +      PRAGMA wal_checkpoint = truncate;
          329  +    }
          330  +    code1 { set ::res2 }
          331  +  } {hello world ! world hello}
          332  +
          333  +  do_test 5.3 {
          334  +    code1 { db close }
          335  +    code1 { tvfs delete }
          336  +  } {}
          337  +
   198    338   
   199    339   }
   200    340   
   201    341   finish_test