/ Check-in [ff0ff75c]
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 | SQL archive
Timelines: family | ancestors | descendants | both | av-defense
Files: files | file ages | folders
SHA1: ff0ff75c3559f5bbe29c73204cc8ff1cb80f42cb
User & Date: drh 2011-07-12 13:51:05
Context
2011-07-12
14:02
Revise logic in winDelete to check the file prior to attempting to delete it. Closed-Leaf check-in: 36f11acc user: mistachkin tags: av-defense
13:51
Improvements to the logging that occurs on an antivirus I/O retry. check-in: ff0ff75c 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: 89f1848d user: drh tags: av-defense
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_win.c.

   423    423   static int retryIoerr(int *pnRetry){
   424    424     DWORD e;
   425    425     if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){
   426    426       return 0;
   427    427     }
   428    428     e = GetLastError();
   429    429     if( e==ERROR_LOCK_VIOLATION || e==ERROR_SHARING_VIOLATION ){
   430         -    int delay = SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry);
   431         -    sqlite3_log(SQLITE_IOERR, "delay %dms for lock/sharing violation - "
   432         -                              "probably due to antivirus software", delay);
   433         -    Sleep(delay);
          430  +    Sleep(SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry));
   434    431       ++*pnRetry;
   435    432       return 1;
   436    433     }
   437    434     return 0;
   438    435   }
          436  +
          437  +/*
          438  +** Log a I/O error retry episode.
          439  +*/
          440  +static void logIoerr(int nRetry){
          441  +  if( nRetry ){
          442  +    sqlite3_log(SQLITE_IOERR, 
          443  +      "delayed %dms for lock/sharing conflict",
          444  +      SQLITE_WIN32_IOERR_RETRY_DELAY*nRetry*(nRetry+1)/2
          445  +    );
          446  +  }
          447  +}
   439    448   
   440    449   #if SQLITE_OS_WINCE
   441    450   /*************************************************************************
   442    451   ** This section contains code for WinCE only.
   443    452   */
   444    453   /*
   445    454   ** WindowsCE does not have a localtime() function.  So create a
................................................................................
   865    874       return SQLITE_FULL;
   866    875     }
   867    876     while( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
   868    877       if( retryIoerr(&nRetry) ) continue;
   869    878       pFile->lastErrno = GetLastError();
   870    879       return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath);
   871    880     }
          881  +  logIoerr(nRetry);
   872    882     if( nRead<(DWORD)amt ){
   873    883       /* Unread parts of the buffer must be zero-filled */
   874    884       memset(&((char*)pBuf)[nRead], 0, amt-nRead);
   875    885       return SQLITE_IOERR_SHORT_READ;
   876    886     }
   877    887   
   878    888     return SQLITE_OK;
................................................................................
   886    896     sqlite3_file *id,               /* File to write into */
   887    897     const void *pBuf,               /* The bytes to be written */
   888    898     int amt,                        /* Number of bytes to write */
   889    899     sqlite3_int64 offset            /* Offset into the file to begin writing at */
   890    900   ){
   891    901     int rc;                         /* True if error has occured, else false */
   892    902     winFile *pFile = (winFile*)id;  /* File handle */
          903  +  int nRetry = 0;                 /* Number of retries */
   893    904   
   894    905     assert( amt>0 );
   895    906     assert( pFile );
   896    907     SimulateIOError(return SQLITE_IOERR_WRITE);
   897    908     SimulateDiskfullError(return SQLITE_FULL);
   898    909   
   899    910     OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
   900    911   
   901    912     rc = seekWinFile(pFile, offset);
   902    913     if( rc==0 ){
   903    914       u8 *aRem = (u8 *)pBuf;        /* Data yet to be written */
   904    915       int nRem = amt;               /* Number of bytes yet to be written */
   905    916       DWORD nWrite;                 /* Bytes written by each WriteFile() call */
   906         -    int nRetry = 0;               /* Number of retries */
   907    917   
   908    918       while( nRem>0 ){
   909    919         if( !WriteFile(pFile->h, aRem, nRem, &nWrite, 0) ){
   910    920           if( retryIoerr(&nRetry) ) continue;
   911    921           break;
   912    922         }
   913    923         if( nWrite<=0 ) break;
................................................................................
   922    932   
   923    933     if( rc ){
   924    934       if(   ( pFile->lastErrno==ERROR_HANDLE_DISK_FULL )
   925    935          || ( pFile->lastErrno==ERROR_DISK_FULL )){
   926    936         return SQLITE_FULL;
   927    937       }
   928    938       return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath);
          939  +  }else{
          940  +    logIoerr(nRetry);
   929    941     }
   930    942     return SQLITE_OK;
   931    943   }
   932    944   
   933    945   /*
   934    946   ** Truncate an open file to a specified size
   935    947   */
................................................................................
  2382   2394   ** it's important to not reference them for WINCE builds.
  2383   2395   */
  2384   2396   #if SQLITE_OS_WINCE==0
  2385   2397     }else{
  2386   2398       while( (rc = DeleteFileW(zConverted))!=0 || retryIoerr(&cnt) ){}
  2387   2399   #endif
  2388   2400     }
  2389         -  if( rc ) rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
         2401  +  if( rc ){
         2402  +    rc = winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename);
         2403  +  }else{
         2404  +    logIoerr(cnt);
         2405  +  }
  2390   2406     free(zConverted);
  2391   2407     OSTRACE(("DELETE \"%s\" %s\n", zFilename, (rc ? "failed" : "ok" )));
  2392   2408     return rc;
  2393   2409   }
  2394   2410   
  2395   2411   /*
  2396   2412   ** Check the existance and status of a file.

Changes to test/win32lock.test.

    16     16   if {$tcl_platform(platform)!="windows"} return
    17     17   
    18     18   set testdir [file dirname $argv0]
    19     19   source $testdir/tester.tcl
    20     20   
    21     21   set testprefix win32lock
    22     22   
           23  +db close
           24  +sqlite3_shutdown
           25  +test_sqlite3_log xLog
           26  +proc xLog {error_code msg} {
           27  +  lappend ::log $msg 
           28  +}
           29  +sqlite3 db test.db
           30  +
    23     31   do_test win32lock-1.1 {
    24     32     db eval {
    25     33       PRAGMA cache_size=10;
    26     34       CREATE TABLE t1(x,y);
    27     35       INSERT INTO t1 VALUES(1,randomblob(100000));
    28     36       INSERT INTO t1 VALUES(2,randomblob(50000));
    29     37       INSERT INTO t1 VALUES(3,randomblob(25000));
................................................................................
    45     53          set ::msg
    46     54       } {disk I/O error}
    47     55       break
    48     56     } else {
    49     57       do_test win32lock-1.2-$delay1 {
    50     58          set ::msg
    51     59       } {1 100000 2 50000 3 25000 4 12500}
           60  +    if {$::log!=""} {
           61  +      do_test win32lock-1.2-$delay1-log1 {
           62  +        regsub {\d+} $::log # x
           63  +        set x
           64  +      } {{delayed #ms for lock/sharing conflict}}
           65  +    }
    52     66       incr delay1 50
    53     67     }
           68  +  set ::log {}
    54     69   }
    55     70   sqlite3_test_control_pending_byte $old_pending_byte
    56         -
           71  +sqlite3_shutdown
           72  +test_sqlite3_log 
           73  +sqlite3_initialize
    57     74   finish_test