/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/os_win.c.

410
411
412
413
414
415
416


417
418
419
420
421
422
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
....
1351
1352
1353
1354
1355
1356
1357














1358
1359
1360
1361
1362
1363
1364
*/
#ifndef SQLITE_WIN32_IOERR_RETRY
# define SQLITE_WIN32_IOERR_RETRY 10
#endif
#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
#endif



/*
** If a ReadFile() or WriteFile() error occurs, invoke this routine
** to see if it should be retried.  Return TRUE to retry.  Return FALSE
** to give up with an error.
*/
static int retryIoerr(int *pnRetry){
  DWORD e;
  if( *pnRetry>=SQLITE_WIN32_IOERR_RETRY ){
    return 0;
  }
  e = GetLastError();
  if( e==ERROR_ACCESS_DENIED ||
      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.
................................................................................
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;














    }
  }
  return SQLITE_NOTFOUND;
}

/*
** Return the sector size in bytes of the underlying block device for







>
>








|






|













|







 







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







410
411
412
413
414
415
416
417
418
419
420
421
422
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
455
....
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
*/
#ifndef SQLITE_WIN32_IOERR_RETRY
# define SQLITE_WIN32_IOERR_RETRY 10
#endif
#ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
# define SQLITE_WIN32_IOERR_RETRY_DELAY 25
#endif
static int win32IoerrRetry = SQLITE_WIN32_IOERR_RETRY;
static int win32IoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;

/*
** If a ReadFile() or WriteFile() error occurs, invoke this routine
** to see if it should be retried.  Return TRUE to retry.  Return FALSE
** to give up with an error.
*/
static int retryIoerr(int *pnRetry){
  DWORD e;
  if( *pnRetry>=win32IoerrRetry ){
    return 0;
  }
  e = GetLastError();
  if( e==ERROR_ACCESS_DENIED ||
      e==ERROR_LOCK_VIOLATION ||
      e==ERROR_SHARING_VIOLATION ){
    Sleep(win32IoerrRetryDelay*(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",
      win32IoerrRetryDelay*nRetry*(nRetry+1)/2
    );
  }
}

#if SQLITE_OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
................................................................................
      SimulateIOErrorBenign(1);
      winTruncate(id, sz);
      SimulateIOErrorBenign(0);
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_SYNC_OMITTED: {
      return SQLITE_OK;
    }
    case SQLITE_FCNTL_WIN32_AV_RETRY: {
      int *a = (int*)pArg;
      if( a[0]>0 ){
        win32IoerrRetry = a[0];
      }else{
        a[0] = win32IoerrRetry;
      }
      if( a[1]>0 ){
        win32IoerrRetryDelay = a[1];
      }else{
        a[1] = win32IoerrRetryDelay;
      }
      return SQLITE_OK;
    }
  }
  return SQLITE_NOTFOUND;
}

/*
** Return the sector size in bytes of the underlying block device for

Changes to src/sqlite.h.in.

732
733
734
735
736
737
738

















739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
** when the database connection has [PRAGMA synchronous] set to OFF.)^
** Some specialized VFSes need this signal in order to operate correctly
** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most 
** VFSes do not need this signal and should silently ignore this opcode.
** Applications should not call [sqlite3_file_control()] with this
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.  

















*/
#define SQLITE_FCNTL_LOCKSTATE        1
#define SQLITE_GET_LOCKPROXYFILE      2
#define SQLITE_SET_LOCKPROXYFILE      3
#define SQLITE_LAST_ERRNO             4
#define SQLITE_FCNTL_SIZE_HINT        5
#define SQLITE_FCNTL_CHUNK_SIZE       6
#define SQLITE_FCNTL_FILE_POINTER     7
#define SQLITE_FCNTL_SYNC_OMITTED     8


/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only







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









|







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

/*
** CAPI3REF: Mutex Handle
**
** The mutex module within SQLite defines [sqlite3_mutex] to be an
** abstract type for a mutex object.  The SQLite core never looks
** at the internal representation of an [sqlite3_mutex].  It only

Changes to src/test1.c.

5092
5093
5094
5095
5096
5097
5098

































5099
5100
5101
5102
5103
5104
5105
....
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
....
5657
5658
5659
5660
5661
5662
5663

5664
5665
5666
5667
5668
5669
5670
....
5888
5889
5890
5891
5892
5893
5894
5895

5896
5897
5898
5899
5900
5901
5902
      return TCL_ERROR;
    }
  }
#endif
  return TCL_OK;  
}



































/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
  if( objc==1 ){
    char zBuf[200];
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
                     x.ok, x.err, x.delay1, x.delay2, x.h);
    Tcl_AppendResult(interp, zBuf, (char*)0);
    return TCL_OK;
  }
  while( x.h && retry<10 ){
    retry++;
    Sleep(100);
  }
  if( x.h ){
    Tcl_AppendResult(interp, "busy", (char*)0);
    return TCL_ERROR;
  }
................................................................................
    return TCL_ERROR;
  }
  _beginthread(win32_file_locker, 0, (void*)&x);
  Sleep(0);
  return TCL_OK;
}
#endif


/*
**      optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()
** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
** OPT is the name of the optimization to be disabled.
................................................................................
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test", file_control_sizehint_test,  0   },

     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },







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







 







|







 







>







 







|
>







5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
....
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
....
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
....
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
      return TCL_ERROR;
    }
  }
#endif
  return TCL_OK;  
}

/*
** tclcmd:   file_control_win32_av_retry DB  NRETRY  DELAY
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_WIN32_AV_RETRY opcode.
*/
static int file_control_win32_av_retry(
  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
  int objc,              /* Number of arguments */
  Tcl_Obj *CONST objv[]  /* Command arguments */
){
  sqlite3 *db;
  int rc;
  int a[2];
  char z[100];

  if( objc!=4 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"",
        Tcl_GetStringFromObj(objv[0], 0), " DB NRETRY DELAY", 0);
    return TCL_ERROR;
  }
  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
    return TCL_ERROR;
  }
  if( Tcl_GetIntFromObj(interp, objv[2], &a[0]) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[3], &a[1]) ) return TCL_ERROR;
  rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_WIN32_AV_RETRY, (void*)a);
  sqlite3_snprintf(sizeof(z), z, "%d %d %d", rc, a[0], a[1]);
  Tcl_AppendResult(interp, z, (char*)0);
  return TCL_OK;  
}


/*
** tclcmd:   sqlite3_vfs_list
**
**   Return a tcl list containing the names of all registered vfs's.
*/
static int vfs_list(
................................................................................
  if( objc==1 ){
    char zBuf[200];
    sqlite3_snprintf(sizeof(zBuf), zBuf, "%d %d %d %d %d",
                     x.ok, x.err, x.delay1, x.delay2, x.h);
    Tcl_AppendResult(interp, zBuf, (char*)0);
    return TCL_OK;
  }
  while( x.h && retry<30 ){
    retry++;
    Sleep(100);
  }
  if( x.h ){
    Tcl_AppendResult(interp, "busy", (char*)0);
    return TCL_ERROR;
  }
................................................................................
    return TCL_ERROR;
  }
  _beginthread(win32_file_locker, 0, (void*)&x);
  Sleep(0);
  return TCL_OK;
}
#endif


/*
**      optimization_control DB OPT BOOLEAN
**
** Enable or disable query optimizations using the sqlite3_test_control()
** interface.  Disable if BOOLEAN is false and enable if BOOLEAN is true.
** OPT is the name of the optimization to be disabled.
................................................................................
     { "vfs_initfail_test",          vfs_initfail_test,   0   },
     { "vfs_unregister_all",         vfs_unregister_all,  0   },
     { "vfs_reregister_all",         vfs_reregister_all,  0   },
     { "file_control_test",          file_control_test,   0   },
     { "file_control_lasterrno_test", file_control_lasterrno_test,  0   },
     { "file_control_lockproxy_test", file_control_lockproxy_test,  0   },
     { "file_control_chunksize_test", file_control_chunksize_test,  0   },
     { "file_control_sizehint_test",  file_control_sizehint_test,   0   },
     { "file_control_win32_av_retry", file_control_win32_av_retry,  0   },
     { "sqlite3_vfs_list",           vfs_list,     0   },
     { "sqlite3_create_function_v2", test_create_function_v2, 0 },

     /* Functions from os.h */
#ifndef SQLITE_OMIT_UTF16
     { "add_test_collate",        test_collate, 0            },
     { "add_test_collate_needed", test_collate_needed, 0     },

Changes to test/win32lock.test.

63
64
65
66
67
68
69


































70
71
72
73
74
        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







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





63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
        set x
      } {{delayed #ms for lock/sharing conflict}}
    }
    incr delay1 50
  }
  set ::log {}
}

do_test win32lock-2.0 {
  file_control_win32_av_retry db -1 -1
} {0 10 25}
do_test win32lock-2.1 {
  file_control_win32_av_retry db 1 1
} {0 1 1}

set delay1 50
while {1} {
  sqlite3_sleep 10
  lock_win32_file test.db 0 $::delay1
  set rc [catch {db eval {SELECT x, length(y) FROM t1 ORDER BY rowid}} msg]
  if {$rc} {
    do_test win32lock-2.2-$delay1-fin {
       set ::msg
    } {disk I/O error}
    break
  } else {
    do_test win32lock-2.2-$delay1 {
       set ::msg
    } {1 100000 2 50000 3 25000 4 12500}
    if {$::log!=""} {
      do_test win32lock-2.2-$delay1-log1 {
        regsub {\d+} $::log # x
        set x
      } {{delayed #ms for lock/sharing conflict}}
    }
    incr delay1 50
  }
  set ::log {}
}

file_control_win32_av_retry db 10 25
sqlite3_test_control_pending_byte $old_pending_byte
sqlite3_shutdown
test_sqlite3_log 
sqlite3_initialize
finish_test