/ Check-in [7aaf0a6a]
Login

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

Overview
Comment:Added the SQLITE_FCNTL_WIN32_AV_RETRY file control for configuring the retry counts and delays in the windows VFS.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7aaf0a6ae1238129e07eb191ca3f043df445e27a
User & Date: drh 2011-07-13 16:03:46
Context
2011-07-13
18:31
Do not try to use STAT2 to refine the row estimate of a query that uses a unique or nearly-unique index. check-in: efffc49b user: drh tags: trunk
16:03
Added the SQLITE_FCNTL_WIN32_AV_RETRY file control for configuring the retry counts and delays in the windows VFS. check-in: 7aaf0a6a user: drh tags: trunk
2011-07-12
14:38
Merge the improved anti-virus defenses into the trunk. check-in: 0207fd9b user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/os_win.c.

   410    410   */
   411    411   #ifndef SQLITE_WIN32_IOERR_RETRY
   412    412   # define SQLITE_WIN32_IOERR_RETRY 10
   413    413   #endif
   414    414   #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
   415    415   # define SQLITE_WIN32_IOERR_RETRY_DELAY 25
   416    416   #endif
          417  +static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
          418  +static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
   417    419   
   418    420   /*
   419    421   ** If a ReadFile() or WriteFile() error occurs, invoke this routine
   420    422   ** to see if it should be retried.  Return TRUE to retry.  Return FALSE
   421    423   ** to give up with an error.
   422    424   */
   423    425   static int retryIoerr(int *pnRetry){
   424    426     DWORD e;
   425         -  if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){
          427  +  if( *pnRetry>=win32IoerrRetry ){
   426    428       return 0;
   427    429     }
   428    430     e = GetLastError();
   429    431     if( e==ERROR_ACCESS_DENIED ||
   430    432         e==ERROR_LOCK_VIOLATION ||
   431    433         e==ERROR_SHARING_VIOLATION ){
   432         -    Sleep(SQLITE_WIN32_IOERR_RETRY_DELAY*(1+*pnRetry));
          434  +    Sleep(win32IoerrRetryDelay*(1+*pnRetry));
   433    435       ++*pnRetry;
   434    436       return 1;
   435    437     }
   436    438     return 0;
   437    439   }
   438    440   
   439    441   /*
   440    442   ** Log a I/O error retry episode.
   441    443   */
   442    444   static void logIoerr(int nRetry){
   443    445     if( nRetry ){
   444    446       sqlite3_log(SQLITE_IOERR, 
   445    447         "delayed %dms for lock/sharing conflict",
   446         -      SQLITE_WIN32_IOERR_RETRY_DELAY*nRetry*(nRetry+1)/2
          448  +      win32IoerrRetryDelay*nRetry*(nRetry+1)/2
   447    449       );
   448    450     }
   449    451   }
   450    452   
   451    453   #if SQLITE_OS_WINCE
   452    454   /*************************************************************************
   453    455   ** This section contains code for WinCE only.
................................................................................
  1351   1353         SimulateIOErrorBenign(1);
  1352   1354         winTruncate(id, sz);
  1353   1355         SimulateIOErrorBenign(0);
  1354   1356         return SQLITE_OK;
  1355   1357       }
  1356   1358       case SQLITE_FCNTL_SYNC_OMITTED: {
  1357   1359         return SQLITE_OK;
         1360  +    }
         1361  +    case SQLITE_FCNTL_WIN32_AV_RETRY: {
         1362  +      int *a = (int*)pArg;
         1363  +      if( a[0]>0 ){
         1364  +        win32IoerrRetry = a[0];
         1365  +      }else{
         1366  +        a[0] = win32IoerrRetry;
         1367  +      }
         1368  +      if( a[1]>0 ){
         1369  +        win32IoerrRetryDelay = a[1];
         1370  +      }else{
         1371  +        a[1] = win32IoerrRetryDelay;
         1372  +      }
         1373  +      return SQLITE_OK;
  1358   1374       }
  1359   1375     }
  1360   1376     return SQLITE_NOTFOUND;
  1361   1377   }
  1362   1378   
  1363   1379   /*
  1364   1380   ** Return the sector size in bytes of the underlying block device for

Changes to src/sqlite.h.in.

   732    732   ** when the database connection has [PRAGMA synchronous] set to OFF.)^
   733    733   ** Some specialized VFSes need this signal in order to operate correctly
   734    734   ** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
   735    735   ** VFSes do not need this signal and should silently ignore this opcode.
   736    736   ** Applications should not call [sqlite3_file_control()] with this
   737    737   ** opcode as doing so may disrupt the operation of the specialized VFSes
   738    738   ** that do require it.  
          739  +**
          740  +** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
          741  +** retry counts and intervals for certain disk I/O operations for the
          742  +** windows [VFS] in order to work to provide robustness against
          743  +** anti-virus programs.  By default, the windows VFS will retry file read,
          744  +** file write, and file delete opertions up to 10 times, with a delay
          745  +** of 25 milliseconds before the first retry and with the delay increasing
          746  +** by an additional 25 milliseconds with each subsequent retry.  This
          747  +** opcode allows those to values (10 retries and 25 milliseconds of delay)
          748  +** to be adjusted.  The values are changed for all database connections
          749  +** within the same process.  The argument is a pointer to an array of two
          750  +** integers where the first integer i the new retry count and the second
          751  +** integer is the delay.  If either integer is negative, then the setting
          752  +** is not changed but instead the prior value of that setting is written
          753  +** into the array entry, allowing the current retry settings to be
          754  +** interrogated.  The zDbName parameter is ignored.
          755  +** 
   739    756   */
   740    757   #define SQLITE_FCNTL_LOCKSTATE        1
   741    758   #define SQLITE_GET_LOCKPROXYFILE      2
   742    759   #define SQLITE_SET_LOCKPROXYFILE      3
   743    760   #define SQLITE_LAST_ERRNO             4
   744    761   #define SQLITE_FCNTL_SIZE_HINT        5
   745    762   #define SQLITE_FCNTL_CHUNK_SIZE       6
   746    763   #define SQLITE_FCNTL_FILE_POINTER     7
   747    764   #define SQLITE_FCNTL_SYNC_OMITTED     8
   748         -
          765  +#define SQLITE_FCNTL_WIN32_AV_RETRY   9
   749    766   
   750    767   /*
   751    768   ** CAPI3REF: Mutex Handle
   752    769   **
   753    770   ** The mutex module within SQLite defines [sqlite3_mutex] to be an
   754    771   ** abstract type for a mutex object.  The SQLite core never looks
   755    772   ** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/test1.c.

  5092   5092         return TCL_ERROR;
  5093   5093       }
  5094   5094     }
  5095   5095   #endif
  5096   5096     return TCL_OK;  
  5097   5097   }
  5098   5098   
         5099  +/*
         5100  +** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
         5101  +**
         5102  +** This TCL command runs the sqlite3_file_control interface with
         5103  +** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
         5104  +*/
         5105  +static int file_control_win32_av_retry(
         5106  +  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
         5107  +  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
         5108  +  int objc,              /* Number of arguments */
         5109  +  Tcl_Obj *CONST objv[]  /* Command arguments */
         5110  +){
         5111  +  sqlite3 *db;
         5112  +  int rc;
         5113  +  int a[2];
         5114  +  char z[100];
         5115  +
         5116  +  if( objc!=4 ){
         5117  +    Tcl_AppendResult(interp, "wrong # args: should be \"",
         5118  +        Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
         5119  +    return TCL_ERROR;
         5120  +  }
         5121  +  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
         5122  +    return TCL_ERROR;
         5123  +  }
         5124  +  if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR;
         5125  +  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
         5126  +  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
         5127  +  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
         5128  +  Tcl_AppendResult(interp, z, (char*)0);
         5129  +  return TCL_OK;  
         5130  +}
         5131  +
  5099   5132   
  5100   5133   /*
  5101   5134   ** tclcmd:   sqlite3_vfs_list
  5102   5135   **
  5103   5136   **   Return a tcl list containing the names of all registered vfs's.
  5104   5137   */
  5105   5138   static int vfs_list(
................................................................................
  5634   5667     if( objc==1 ){
  5635   5668       char zBuf[200];
  5636   5669       sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
  5637   5670                        x.ok, x.err, x.delay1, x.delay2, x.h);
  5638   5671       Tcl_AppendResult(interp, zBuf, (char*)0);
  5639   5672       return TCL_OK;
  5640   5673     }
  5641         -  while( x.h && retry<10 ){
         5674  +  while( x.h && retry<30 ){
  5642   5675       retry++;
  5643   5676       Sleep(100);
  5644   5677     }
  5645   5678     if( x.h ){
  5646   5679       Tcl_AppendResult(interp, "busy", (char*)0);
  5647   5680       return TCL_ERROR;
  5648   5681     }
................................................................................
  5657   5690       return TCL_ERROR;
  5658   5691     }
  5659   5692     _beginthread(win32_file_locker, 0, (void*)&x);
  5660   5693     Sleep(0);
  5661   5694     return TCL_OK;
  5662   5695   }
  5663   5696   #endif
         5697  +
  5664   5698   
  5665   5699   /*
  5666   5700   **      optimization_control DB OPT BOOLEAN
  5667   5701   **
  5668   5702   ** Enable or disable query optimizations using the sqlite3_test_control()
  5669   5703   ** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
  5670   5704   ** OPT is the name of the optimization to be disabled.
................................................................................
  5889   5923        { "vfs_unregister_all",         vfs_unregister_all,  0   },
  5890   5924        { "vfs_reregister_all",         vfs_reregister_all,  0   },
  5891   5925        { "file_control_test",          file_control_test,   0   },
  5892   5926        { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
  5893   5927        { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
  5894   5928        { "file_control_chunksize_test", file_control_chunksize_test,  0   },
  5895   5929        { "file_control_sizehint_test", file_control_sizehint_test,  0   },
         5930  +     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
  5896   5931        { "sqlite3_vfs_list",           vfs_list,     0   },
  5897   5932        { "sqlite3_create_function_v2", test_create_function_v2, 0 },
  5898   5933   
  5899   5934        /* Functions from os.h */
  5900   5935   #ifndef SQLITE_OMIT_UTF16
  5901   5936        { "add_test_collate",        test_collate, 0            },
  5902   5937        { "add_test_collate_needed", test_collate_needed, 0     },

Changes to test/win32lock.test.

    63     63           set x
    64     64         } {{delayed #ms for lock/sharing conflict}}
    65     65       }
    66     66       incr delay1 50
    67     67     }
    68     68     set ::log {}
    69     69   }
           70  +
           71  +do_test win32lock-2.0 {
           72  +  file_control_win32_av_retry db -1 -1
           73  +} {0 10 25}
           74  +do_test win32lock-2.1 {
           75  +  file_control_win32_av_retry db 1 1
           76  +} {0 1 1}
           77  +
           78  +set delay1 50
           79  +while {1} {
           80  +  sqlite3_sleep 10
           81  +  lock_win32_file test.db 0 $::delay1
           82  +  set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg]
           83  +  if {$rc} {
           84  +    do_test win32lock-2.2-$delay1-fin {
           85  +       set ::msg
           86  +    } {disk I/O error}
           87  +    break
           88  +  } else {
           89  +    do_test win32lock-2.2-$delay1 {
           90  +       set ::msg
           91  +    } {1 100000 2 50000 3 25000 4 12500}
           92  +    if {$::log!=""} {
           93  +      do_test win32lock-2.2-$delay1-log1 {
           94  +        regsub {\d+} $::log # x
           95  +        set x
           96  +      } {{delayed #ms for lock/sharing conflict}}
           97  +    }
           98  +    incr delay1 50
           99  +  }
          100  +  set ::log {}
          101  +}
          102  +
          103  +file_control_win32_av_retry db 10 25
    70    104   sqlite3_test_control_pending_byte $old_pending_byte
    71    105   sqlite3_shutdown
    72    106   test_sqlite3_log 
    73    107   sqlite3_initialize
    74    108   finish_test