SQLite

Check-in [ff0ff75c35]
Login

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

Overview
Comment:Improvements to the logging that occurs on an antivirus I/O retry.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | av-defense
Files: files | file ages | folders
SHA1: ff0ff75c3559f5bbe29c73204cc8ff1cb80f42cb
User & Date: drh 2011-07-12 13:51:05.210
Context
2011-07-12
14:02
Revise logic in winDelete to check the file prior to attempting to delete it. (Closed-Leaf check-in: 36f11acc53 user: mistachkin tags: av-defense)
13:51
Improvements to the logging that occurs on an antivirus I/O retry. (check-in: ff0ff75c35 user: drh tags: av-defense)
11:04
Update the anti-virus retry logic for DeleteFile(). Invoke sqlite3_log() for each anti-virus retry. Make the retry delay configurable at compile-time. (check-in: 89f1848d7f user: drh tags: av-defense)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/os_win.c.
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438












439
440
441
442
443
444
445
static int retryIoerr(int *pnRetry){
  DWORD e;
  if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){
    return 0;
  }
  e = GetLastError();
  if( e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){
    int delay = SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry);
    sqlite3_log(SQLITE_IOERR, "delay %dms for lock/sharing violation - "
                              "probably due to antivirus software", delay);
    Sleep(delay);
    ++*pnRetry;
    return 1;
  }
  return 0;
}













#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a localtime() function.  So create a







|
<
<
<





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







423
424
425
426
427
428
429
430



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
static int retryIoerr(int *pnRetry){
  DWORD e;
  if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){
    return 0;
  }
  e = GetLastError();
  if( e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){
    Sleep(SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry));



    ++*pnRetry;
    return 1;
  }
  return 0;
}

/*
** Log a I/O error retry episode.
*/
static void logIoerr(int nRetry){
  if( nRetry ){
    sqlite3_log(SQLITE_IOERR, 
      "delayed %dms for lock/sharing conflict",
      SQLITE_WIN32_IOERR_RETRY_DELAY*nRetry*(nRetry+1)/2
    );
  }
}

#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
*/
/*
** WindowsCE does not have a localtime() function.  So create a
865
866
867
868
869
870
871

872
873
874
875
876
877
878
    return SQLITE_FULL;
  }
  while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
    if( retryIoerr(&nRetry) ) continue;
    pFile->lastErrno = GetLastError();
    return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
  }

  if( nRead<(DWORD)amt ){
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[nRead], 0, amt-nRead);
    return SQLITE_IOERR_SHORT_READ;
  }

  return SQLITE_OK;







>







874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
    return SQLITE_FULL;
  }
  while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
    if( retryIoerr(&nRetry) ) continue;
    pFile->lastErrno = GetLastError();
    return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
  }
  logIoerr(nRetry);
  if( nRead<(DWORD)amt ){
    /* Unread parts of the buffer must be zero-filled */
    memset(&((char*)pBuf)[nRead], 0, amt-nRead);
    return SQLITE_IOERR_SHORT_READ;
  }

  return SQLITE_OK;
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
  sqlite3_file *id,               /* File to write into */
  const void *pBuf,               /* The bytes to be written */
  int amt,                        /* Number of bytes to write */
  sqlite3_int64 offset            /* Offset into the file to begin writing at */
){
  int rc;                         /* True if error has occured, else false */
  winFile *pFile = (winFile*)id;  /* File handle */


  assert( amt>0 );
  assert( pFile );
  SimulateIOError(return SQLITE_IOERR_WRITE);
  SimulateDiskfullError(return SQLITE_FULL);

  OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));

  rc = seekWinFile(pFile, offset);
  if( rc==0 ){
    u8 *aRem = (u8 *)pBuf;        /* Data yet to be written */
    int nRem = amt;               /* Number of bytes yet to be written */
    DWORD nWrite;                 /* Bytes written by each WriteFile() call */
    int nRetry = 0;               /* Number of retries */

    while( nRem>0 ){
      if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
        if( retryIoerr(&nRetry) ) continue;
        break;
      }
      if( nWrite<=0 ) break;







>













<







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
  sqlite3_file *id,               /* File to write into */
  const void *pBuf,               /* The bytes to be written */
  int amt,                        /* Number of bytes to write */
  sqlite3_int64 offset            /* Offset into the file to begin writing at */
){
  int rc;                         /* True if error has occured, else false */
  winFile *pFile = (winFile*)id;  /* File handle */
  int nRetry = 0;                 /* Number of retries */

  assert( amt>0 );
  assert( pFile );
  SimulateIOError(return SQLITE_IOERR_WRITE);
  SimulateDiskfullError(return SQLITE_FULL);

  OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));

  rc = seekWinFile(pFile, offset);
  if( rc==0 ){
    u8 *aRem = (u8 *)pBuf;        /* Data yet to be written */
    int nRem = amt;               /* Number of bytes yet to be written */
    DWORD nWrite;                 /* Bytes written by each WriteFile() call */


    while( nRem>0 ){
      if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
        if( retryIoerr(&nRetry) ) continue;
        break;
      }
      if( nWrite<=0 ) break;
922
923
924
925
926
927
928


929
930
931
932
933
934
935

  if( rc ){
    if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
       || ( pFile->lastErrno==ERROR_DISK_FULL )){
      return SQLITE_FULL;
    }
    return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);


  }
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/







>
>







932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947

  if( rc ){
    if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
       || ( pFile->lastErrno==ERROR_DISK_FULL )){
      return SQLITE_FULL;
    }
    return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
  }else{
    logIoerr(nRetry);
  }
  return SQLITE_OK;
}

/*
** Truncate an open file to a specified size
*/
2382
2383
2384
2385
2386
2387
2388

2389



2390
2391
2392
2393
2394
2395
2396
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
  }else{
    while( (rc = DeleteFileW(zConverted))!=0 || retryIoerr(&cnt) ){}
#endif
  }

  if( rc ) rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);



  free(zConverted);
  OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
  return rc;
}

/*
** Check the existance and status of a file.







>
|
>
>
>







2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
** it's important to not reference them for WINCE builds.
*/
#if SQLITE_OS_WINCE==0
  }else{
    while( (rc = DeleteFileW(zConverted))!=0 || retryIoerr(&cnt) ){}
#endif
  }
  if( rc ){
    rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
  }else{
    logIoerr(cnt);
  }
  free(zConverted);
  OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
  return rc;
}

/*
** Check the existance and status of a file.
Changes to test/win32lock.test.
16
17
18
19
20
21
22








23
24
25
26
27
28
29
if {$tcl_platform(platform)!="windows"} return

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set testprefix win32lock









do_test win32lock-1.1 {
  db eval {
    PRAGMA cache_size=10;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(1,randomblob(100000));
    INSERT INTO t1 VALUES(2,randomblob(50000));
    INSERT INTO t1 VALUES(3,randomblob(25000));







>
>
>
>
>
>
>
>







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
if {$tcl_platform(platform)!="windows"} return

set testdir [file dirname $argv0]
source $testdir/tester.tcl

set testprefix win32lock

db close
sqlite3_shutdown
test_sqlite3_log xLog
proc xLog {error_code msg} {
  lappend ::log $msg 
}
sqlite3 db test.db

do_test win32lock-1.1 {
  db eval {
    PRAGMA cache_size=10;
    CREATE TABLE t1(x,y);
    INSERT INTO t1 VALUES(1,randomblob(100000));
    INSERT INTO t1 VALUES(2,randomblob(50000));
    INSERT INTO t1 VALUES(3,randomblob(25000));
45
46
47
48
49
50
51






52
53

54
55
56


57
       set ::msg
    } {disk I/O error}
    break
  } else {
    do_test win32lock-1.2-$delay1 {
       set ::msg
    } {1 100000 2 50000 3 25000 4 12500}






    incr delay1 50
  }

}
sqlite3_test_control_pending_byte $old_pending_byte



finish_test







>
>
>
>
>
>


>


|
>
>

53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
       set ::msg
    } {disk I/O error}
    break
  } else {
    do_test win32lock-1.2-$delay1 {
       set ::msg
    } {1 100000 2 50000 3 25000 4 12500}
    if {$::log!=""} {
      do_test win32lock-1.2-$delay1-log1 {
        regsub {\d+} $::log # x
        set x
      } {{delayed #ms for lock/sharing conflict}}
    }
    incr delay1 50
  }
  set ::log {}
}
sqlite3_test_control_pending_byte $old_pending_byte
sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test