/ Check-in [429f437f]
Login

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

Overview
Comment:Add tests to cover a couple of branches in wal.c.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 429f437fb776fc974a6adf791b729e25bea82fef
User & Date: dan 2010-05-06 14:42:35
Context
2010-05-06
15:36
Update configure scripts for WAL support. check-in: 2edc5129 user: shaneh tags: trunk
14:42
Add tests to cover a couple of branches in wal.c. check-in: 429f437f user: dan tags: trunk
13:36
Unset a tcl variable before reusing it in wal.test. check-in: e83efb23 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/wal.c.

560
561
562
563
564
565
566

567
568
569
570
571
572
573
...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
...
904
905
906
907
908
909
910

911
912
913
914
915
916
917
...
922
923
924
925
926
927
928




929
930
931

932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
....
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
  }else{
    hdr.iCheck1 = 2;
    hdr.iCheck2 = 3;
  }

finished:
  walIndexWriteHdr(pWal, &hdr);

  return rc;
}

/*
** Close an open wal-index.
*/
static void walIndexClose(Wal *pWal, int isDelete){
................................................................................
    int rc;
    rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT);
    if( rc ) return rc;
  }

  /* Read the header. The caller may or may not have locked the wal-index
  ** file, meaning it is possible that an inconsistent snapshot is read
  ** from the file. If this happens, return SQLITE_ERROR. The caller will
  ** retry. Or, if the caller has already locked the file and the header
  ** still looks inconsistent, it will run recovery.
  **
  ** FIX-ME:  It is no longer possible to have not locked the wal-index.
  */
  memcpy(aHdr, pWal->pWiData, sizeof(aHdr));
  walChecksumBytes((u8*)aHdr, sizeof(u32)*WALINDEX_HDR_NFIELD, aCksum);
  if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
   || aCksum[1]!=aHdr[WALINDEX_HDR_NFIELD+1]
  ){
    return SQLITE_OK;
  }
  *pisValid = 1;

  if( memcmp(&pWal->hdr, aHdr, sizeof(WalIndexHdr)) ){
    if( pChanged ){
      *pChanged = 1;
    }
    memcpy(&pWal->hdr, aHdr, sizeof(WalIndexHdr));
  }
  return SQLITE_OK;
}

/*
** Read the wal-index header from the wal-index file into structure 
................................................................................
** Otherwise an SQLite error code.
*/
static int walIndexReadHdr(Wal *pWal, int *pChanged){
  int rc;
  int isValid = 0;

  assert( pWal->lockState>=SQLITE_SHM_READ );

  rc = walIndexMap(pWal, -1);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  /* First try to read the header without a lock. Verify the checksum
  ** before returning. This will almost always work.  
................................................................................
  }

  /* If the first attempt to read the header failed, lock the wal-index
  ** file and try again. If the header checksum verification fails this
  ** time as well, run log recovery.
  */
  if( SQLITE_OK==(rc = walSetLock(pWal, SQLITE_SHM_RECOVER)) ){




    rc = walIndexTryHdr(pWal, &isValid, pChanged);
    if( rc==SQLITE_OK && isValid==0 ){
      if( pChanged ){

        *pChanged = 1;
      }
      rc = walIndexRecover(pWal);
      if( rc==SQLITE_OK ){
        rc = walIndexTryHdr(pWal, &isValid, 0);
      }
    }
    walSetLock(pWal, SQLITE_SHM_READ);
  }

  if( rc==SQLITE_OK && isValid==0 ){
    rc = SQLITE_ERROR;
  }
  return rc;
}

/*
** Lock a snapshot.
**
** If this call obtains a new read-lock and the database contents have been
................................................................................
** other than SQLITE_OK, it is not invoked again and the error code is
** returned to the caller.
**
** Otherwise, if the callback function does not return an error, this
** function returns SQLITE_OK.
*/
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){

  int rc = SQLITE_OK;
  Pgno iMax = pWal->hdr.iLastPg;
  Pgno iFrame;

  rc = walIndexReadHdr(pWal, 0);
  for(iFrame=pWal->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
    assert( pWal->lockState==SQLITE_SHM_WRITE );
    rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
  }
  walIndexUnmap(pWal);
  return rc;
}







>







 







|
<
<
<
<











<
|
<







 







>







 







>
>
>
>

|
<
>
|
<

<
<
<




<
<
<







 







>




|







560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
868
869
870
871
872
873
874
875




876
877
878
879
880
881
882
883
884
885
886

887

888
889
890
891
892
893
894
...
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
...
918
919
920
921
922
923
924
925
926
927
928
929
930

931
932

933



934
935
936
937



938
939
940
941
942
943
944
....
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
  }else{
    hdr.iCheck1 = 2;
    hdr.iCheck2 = 3;
  }

finished:
  walIndexWriteHdr(pWal, &hdr);
  memcpy(&pWal->hdr, &hdr, sizeof(hdr));
  return rc;
}

/*
** Close an open wal-index.
*/
static void walIndexClose(Wal *pWal, int isDelete){
................................................................................
    int rc;
    rc = walIndexRemap(pWal, WALINDEX_MMAP_INCREMENT);
    if( rc ) return rc;
  }

  /* Read the header. The caller may or may not have locked the wal-index
  ** file, meaning it is possible that an inconsistent snapshot is read
  ** from the file. If this happens, return SQLITE_ERROR.




  */
  memcpy(aHdr, pWal->pWiData, sizeof(aHdr));
  walChecksumBytes((u8*)aHdr, sizeof(u32)*WALINDEX_HDR_NFIELD, aCksum);
  if( aCksum[0]!=aHdr[WALINDEX_HDR_NFIELD]
   || aCksum[1]!=aHdr[WALINDEX_HDR_NFIELD+1]
  ){
    return SQLITE_OK;
  }
  *pisValid = 1;

  if( memcmp(&pWal->hdr, aHdr, sizeof(WalIndexHdr)) ){

    *pChanged = 1;

    memcpy(&pWal->hdr, aHdr, sizeof(WalIndexHdr));
  }
  return SQLITE_OK;
}

/*
** Read the wal-index header from the wal-index file into structure 
................................................................................
** Otherwise an SQLite error code.
*/
static int walIndexReadHdr(Wal *pWal, int *pChanged){
  int rc;
  int isValid = 0;

  assert( pWal->lockState>=SQLITE_SHM_READ );
  assert( pChanged );
  rc = walIndexMap(pWal, -1);
  if( rc!=SQLITE_OK ){
    return rc;
  }

  /* First try to read the header without a lock. Verify the checksum
  ** before returning. This will almost always work.  
................................................................................
  }

  /* If the first attempt to read the header failed, lock the wal-index
  ** file and try again. If the header checksum verification fails this
  ** time as well, run log recovery.
  */
  if( SQLITE_OK==(rc = walSetLock(pWal, SQLITE_SHM_RECOVER)) ){
    /* This call to walIndexTryHdr() may not return an error code, as the
    ** wal-index is already mapped. It may find that the header is invalid,
    ** but there is no chance of hitting an actual error.  */
    assert( pWal->szWIndex );
    rc = walIndexTryHdr(pWal, &isValid, pChanged);
    assert( rc==SQLITE_OK );

    if( isValid==0 ){
      *pChanged = 1;

      rc = walIndexRecover(pWal);



    }
    walSetLock(pWal, SQLITE_SHM_READ);
  }




  return rc;
}

/*
** Lock a snapshot.
**
** If this call obtains a new read-lock and the database contents have been
................................................................................
** other than SQLITE_OK, it is not invoked again and the error code is
** returned to the caller.
**
** Otherwise, if the callback function does not return an error, this
** function returns SQLITE_OK.
*/
int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *pUndoCtx){
  int unused;
  int rc = SQLITE_OK;
  Pgno iMax = pWal->hdr.iLastPg;
  Pgno iFrame;

  rc = walIndexReadHdr(pWal, &unused);
  for(iFrame=pWal->hdr.iLastPg+1; iFrame<=iMax && rc==SQLITE_OK; iFrame++){
    assert( pWal->lockState==SQLITE_SHM_WRITE );
    rc = xUndo(pUndoCtx, pWal->pWiData[walIndexEntry(iFrame)]);
  }
  walIndexUnmap(pWal);
  return rc;
}

Changes to test/walfault.test.

205
206
207
208
209
210
211
212

























213
214
  unset ::shmfault_ioerr_methods(xShmGet)
  if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}

  sqlite3 db test.db -vfs shmfault
} -sqlbody {
  SELECT count(*) FROM t1;
}


























finish_test









>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  unset ::shmfault_ioerr_methods(xShmGet)
  if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}

  sqlite3 db test.db -vfs shmfault
} -sqlbody {
  SELECT count(*) FROM t1;
}

do_shmfault_test walfault-shm-4 -tclprep {
  sqlite3 db test.db -vfs shmfault
  unset -nocomplain ::shmfault_ioerr_countdown
  db eval {
    PRAGMA page_size = 512;
    PRAGMA journal_mode = WAL;
    PRAGMA wal_autocheckpoint = 0;
    CREATE TABLE t1(x);
    BEGIN;
      INSERT INTO t1 VALUES(randomblob(400));           /* 1 */
      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 2 */
      INSERT INTO t1 SELECT randomblob(400) FROM t1;    /* 4 */
    COMMIT;
  }

  set ::shmfault_ioerr_countdown 1
  set ::shmfault_ioerr_methods(xShmGet) 1
  db close
  unset ::shmfault_ioerr_methods(xShmGet)
  if {[file exists test.db-wal]==0} {error "Failed to create WAL file!"}
  sqlite3 db test.db -vfs shmfault
} -sqlbody {
  SELECT count(*) FROM t1;
}

finish_test