/ Check-in [5a6703fc]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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 Unified Diffs Ignore Whitespace Patch

Changes to src/wal.c.

2067
2068
2069
2070
2071
2072
2073






2074
2075
2076
2077
2078
2079
2080
....
2145
2146
2147
2148
2149
2150
2151



2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
    testcase( pWal->szPage>=65536 );
  }

  /* The header was successfully read. Return zero. */
  return 0;
}







/*
** Read the wal-index header from the wal-index and into pWal->hdr.
** If the wal-header appears to be corrupt, try to reconstruct the
** wal-index from the WAL before returning.
**
** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
** changed by this operation.  If pWal->hdr is unchanged, set *pChanged
................................................................................
  */
  if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
    rc = SQLITE_CANTOPEN_BKPT;
  }
  if( pWal->bUnlocked ){
    if( rc!=SQLITE_OK ){
      walIndexClose(pWal, 0);



    }
    pWal->exclusiveMode = WAL_NORMAL_MODE;
  }

  return rc;
}

/*
** This is the value that walTryBeginRead returns when it needs to
** be retried.
*/
#define WAL_RETRY  (-1)

/*
** Open an "unlocked" transaction. An unlocked transaction is a read 
** transaction used by a read-only client in cases where the *-shm
** file cannot be mapped and its contents cannot be trusted. It is
** assumed that the *-wal file has been read and that a wal-index 
** constructed in heap memory is currently available in Wal.apWiData[].
**







>
>
>
>
>
>







 







>
>
>







<
<
<
<
<
<







2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
....
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167






2168
2169
2170
2171
2172
2173
2174
    testcase( pWal->szPage>=65536 );
  }

  /* The header was successfully read. Return zero. */
  return 0;
}

/*
** This is the value that walTryBeginRead returns when it needs to
** be retried.
*/
#define WAL_RETRY  (-1)

/*
** Read the wal-index header from the wal-index and into pWal->hdr.
** If the wal-header appears to be corrupt, try to reconstruct the
** wal-index from the WAL before returning.
**
** Set *pChanged to 1 if the wal-index header value in pWal->hdr is
** changed by this operation.  If pWal->hdr is unchanged, set *pChanged
................................................................................
  */
  if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
    rc = SQLITE_CANTOPEN_BKPT;
  }
  if( pWal->bUnlocked ){
    if( rc!=SQLITE_OK ){
      walIndexClose(pWal, 0);
      pWal->bUnlocked = 0;
      assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
      if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
    }
    pWal->exclusiveMode = WAL_NORMAL_MODE;
  }

  return rc;
}







/*
** Open an "unlocked" transaction. An unlocked transaction is a read 
** transaction used by a read-only client in cases where the *-shm
** file cannot be mapped and its contents cannot be trusted. It is
** assumed that the *-wal file has been read and that a wal-index 
** constructed in heap memory is currently available in Wal.apWiData[].
**

Changes to test/walro2.test.

331
332
333
334
335
336
337

338




















































339
340
341
  } {hello world ! world hello}

  do_test 5.3 {
    code1 { db close }
    code1 { tvfs delete }
  } {}























































}

finish_test







>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
  } {hello world ! world hello}

  do_test 5.3 {
    code1 { db close }
    code1 { tvfs delete }
  } {}

  #-----------------------------------------------------------------------
  #
  #
  catch { code1 { db close } }
  catch { code2 { db2 close } }
  catch { code3 { db3 close } }

  do_test 6.1 {
    code1 { forcedelete test.db }
    code1 { sqlite3 db test.db }
    sql1 {
      PRAGMA journal_mode = wal;
      CREATE TABLE t1(x);
      INSERT INTO t1 VALUES('hello');
      INSERT INTO t1 VALUES('world');
      INSERT INTO t1 VALUES('!');
      INSERT INTO t1 VALUES('world');
      INSERT INTO t1 VALUES('hello');
    }

    forcecopy test.db test.db2
    forcecopy test.db-wal test.db2-wal
    forcecopy test.db-shm test.db2-shm
    
    code1 { db close }
  } {}

  do_test 6.2 {
    code1 {
      set ::nRem 5
      proc handle_read {op args} {
        if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} {
          incr ::nRem -1
          if {$::nRem==0} {
            code2 { sqlite3 db2 test.db2 }
            sql2  { PRAGMA wal_checkpoint = truncate }
          }
        }
        return "SQLITE_OK"
      }
      testvfs tvfs -fullshm 1

      tvfs filter xRead
      tvfs script handle_read

      sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs
      db eval { SELECT * FROM t1 }
    }
  } {hello world ! world hello}

  do_test 6.3 {
    code1 { db close }
    code1 { tvfs delete }
  } {}
}

finish_test