SQLite

Check-in [429f437fb7]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 429f437fb776fc974a6adf791b729e25bea82fef
User & Date: dan 2010-05-06 14:42:35.000
Context
2010-05-06
15:36
Update configure scripts for WAL support. (check-in: 2edc5129f2 user: shaneh tags: trunk)
14:42
Add tests to cover a couple of branches in wal.c. (check-in: 429f437fb7 user: dan tags: trunk)
13:36
Unset a tcl variable before reusing it in wal.test. (check-in: e83efb232f user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/wal.c.
560
561
562
563
564
565
566

567
568
569
570
571
572
573
  }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){







>







560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  }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){
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
900
901
902
903
904
905
906
907
908
909
910

911
912
913
914
915
916
917
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
945
946
947
948
949
950
951
    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 
** pWal->hdr. If attempting to verify the header checksum fails, try
** to recover the log before returning.
**
** If the wal-index header is successfully read, return SQLITE_OK. 
** 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.  
  */
  rc = walIndexTryHdr(pWal, &isValid, pChanged);
  if( isValid || rc!=SQLITE_OK ){
    return rc;
  }

  /* 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







|
<
<
<
<











<
|
<


















>


















>
>
>
>

|
|
|
<

<
<
<




<
<
<







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
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
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
    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 
** pWal->hdr. If attempting to verify the header checksum fails, try
** to recover the log before returning.
**
** If the wal-index header is successfully read, return SQLITE_OK. 
** 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.  
  */
  rc = walIndexTryHdr(pWal, &isValid, pChanged);
  if( isValid || rc!=SQLITE_OK ){
    return rc;
  }

  /* 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
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
** 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;
}







>




|







1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
** 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