/ Check-in [5a6703fc]
Login

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

Overview
Comment:Handle the race condition that may occur if another process connects and then checkpoints and truncates the wal file while a readonly-shm client is building its heap-memory wal-index.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | readonly-wal-recovery
Files: files | file ages | folders
SHA3-256: 5a6703fc3f2174b3e9a624c7272ae013b73c42d6c97ffa62b58553efdb54e3bc
User & Date: dan 2017-11-07 21:15:07
Context
2017-11-07
21:25
Update an assert in wal.c. check-in: 94527b89 user: dan tags: readonly-wal-recovery
21:15
Handle the race condition that may occur if another process connects and then checkpoints and truncates the wal file while a readonly-shm client is building its heap-memory wal-index. check-in: 5a6703fc user: dan tags: readonly-wal-recovery
15:43
On unix, if the *-shm file cannot be opened for read/write access, open it read-only and proceed as if the readonly_shm=1 URI option were specified. check-in: ba718754 user: dan tags: readonly-wal-recovery
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/wal.c.

  2067   2067       testcase( pWal->szPage>=65536 );
  2068   2068     }
  2069   2069   
  2070   2070     /* The header was successfully read. Return zero. */
  2071   2071     return 0;
  2072   2072   }
  2073   2073   
         2074  +/*
         2075  +** This is the value that walTryBeginRead returns when it needs to
         2076  +** be retried.
         2077  +*/
         2078  +#define WAL_RETRY  (-1)
         2079  +
  2074   2080   /*
  2075   2081   ** Read the wal-index header from the wal-index and into pWal->hdr.
  2076   2082   ** If the wal-header appears to be corrupt, try to reconstruct the
  2077   2083   ** wal-index from the WAL before returning.
  2078   2084   **
  2079   2085   ** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
  2080   2086   ** changed by this operation.  If pWal->hdr is unchanged, set *pChanged
................................................................................
  2145   2151     */
  2146   2152     if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
  2147   2153       rc = SQLITE_CANTOPEN_BKPT;
  2148   2154     }
  2149   2155     if( pWal->bUnlocked ){
  2150   2156       if( rc!=SQLITE_OK ){
  2151   2157         walIndexClose(pWal, 0);
         2158  +      pWal->bUnlocked = 0;
         2159  +      assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
         2160  +      if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
  2152   2161       }
  2153   2162       pWal->exclusiveMode = WAL_NORMAL_MODE;
  2154   2163     }
  2155   2164   
  2156   2165     return rc;
  2157   2166   }
  2158   2167   
  2159         -/*
  2160         -** This is the value that walTryBeginRead returns when it needs to
  2161         -** be retried.
  2162         -*/
  2163         -#define WAL_RETRY  (-1)
  2164         -
  2165   2168   /*
  2166   2169   ** Open an "unlocked" transaction. An unlocked transaction is a read 
  2167   2170   ** transaction used by a read-only client in cases where the *-shm
  2168   2171   ** file cannot be mapped and its contents cannot be trusted. It is
  2169   2172   ** assumed that the *-wal file has been read and that a wal-index 
  2170   2173   ** constructed in heap memory is currently available in Wal.apWiData[].
  2171   2174   **

Changes to test/walro2.test.

   331    331     } {hello world ! world hello}
   332    332   
   333    333     do_test 5.3 {
   334    334       code1 { db close }
   335    335       code1 { tvfs delete }
   336    336     } {}
   337    337   
          338  +  #-----------------------------------------------------------------------
          339  +  #
          340  +  #
          341  +  catch { code1 { db close } }
          342  +  catch { code2 { db2 close } }
          343  +  catch { code3 { db3 close } }
          344  +
          345  +  do_test 6.1 {
          346  +    code1 { forcedelete test.db }
          347  +    code1 { sqlite3 db test.db }
          348  +    sql1 {
          349  +      PRAGMA journal_mode = wal;
          350  +      CREATE TABLE t1(x);
          351  +      INSERT INTO t1 VALUES('hello');
          352  +      INSERT INTO t1 VALUES('world');
          353  +      INSERT INTO t1 VALUES('!');
          354  +      INSERT INTO t1 VALUES('world');
          355  +      INSERT INTO t1 VALUES('hello');
          356  +    }
          357  +
          358  +    forcecopy test.db test.db2
          359  +    forcecopy test.db-wal test.db2-wal
          360  +    forcecopy test.db-shm test.db2-shm
          361  +    
          362  +    code1 { db close }
          363  +  } {}
          364  +
          365  +  do_test 6.2 {
          366  +    code1 {
          367  +      set ::nRem 5
          368  +      proc handle_read {op args} {
          369  +        if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
          370  +          incr ::nRem -1
          371  +          if {$::nRem==0} {
          372  +            code2 { sqlite3 db2 test.db2 }
          373  +            sql2  { PRAGMA wal_checkpoint = truncate }
          374  +          }
          375  +        }
          376  +        return "SQLITE_OK"
          377  +      }
          378  +      testvfs tvfs -fullshm 1
          379  +
          380  +      tvfs filter xRead
          381  +      tvfs script handle_read
          382  +
          383  +      sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs
          384  +      db eval { SELECT * FROM t1 }
          385  +    }
          386  +  } {hello world ! world hello}
   338    387   
          388  +  do_test 6.3 {
          389  +    code1 { db close }
          390  +    code1 { tvfs delete }
          391  +  } {}
   339    392   }
   340    393   
   341    394   finish_test