/ Check-in [43c31170]
Login
Overview
Comment:Further corrections to read-only SHM file handling on Win32.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | readonly-wal-recovery
Files: files | file ages | folders
SHA3-256:43c311701bdf1202918cd46fa6133a11458e0ef8ddb09e46290a231083f395ce
User & Date: mistachkin 2017-11-09 18:53:51
Context
2017-11-09
20:02
Get read-only SHM file tests passing on Win32. check-in: abef0535 user: mistachkin tags: readonly-wal-recovery
18:53
Further corrections to read-only SHM file handling on Win32. check-in: 43c31170 user: mistachkin tags: readonly-wal-recovery
18:21
Corrections to Win32 lock detection for SHM files. check-in: 3a91be97 user: mistachkin tags: readonly-wal-recovery
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_win.c.

  2101   2101   /*
  2102   2102   ** The "winIsLockingError" macro is used to determine if a particular I/O
  2103   2103   ** error code is due to file locking.  It must accept the error code DWORD
  2104   2104   ** as its only argument and should return non-zero if the error code is due
  2105   2105   ** to file locking.
  2106   2106   */
  2107   2107   #if !defined(winIsLockingError)
  2108         -#define winIsLockingError(a) (((a)==ERROR_ACCESS_DENIED)        || \
         2108  +#define winIsLockingError(a) (((a)==NO_ERROR)                   || \
  2109   2109                                 ((a)==ERROR_LOCK_VIOLATION)       || \
         2110  +                              ((a)==ERROR_HANDLE_EOF)           || \
  2110   2111                                 ((a)==ERROR_IO_PENDING))
  2111   2112   #endif
  2112   2113   
  2113   2114   /*
  2114   2115   ** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
  2115   2116   ** error code obtained via GetLastError() is eligible to be retried.  It
  2116   2117   ** must accept the error code DWORD as its only argument and should return
................................................................................
  3843   3844   **
  3844   3845   **       WINSHM_UNLCK -- No locks are held on the DMS.
  3845   3846   **       WINSHM_RDLCK -- A SHARED lock is held on the DMS.
  3846   3847   **       WINSHM_WRLCK -- An EXCLUSIVE lock is held on the DMS.
  3847   3848   */
  3848   3849   static int winGetShmDmsLockType(
  3849   3850     winFile *pFile, /* File handle object */
         3851  +  int bReadOnly,  /* Non-zero if the SHM was opened read-only */
  3850   3852     int *pLockType  /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
  3851   3853   ){
  3852   3854   #if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
  3853   3855     OVERLAPPED overlapped; /* The offset for ReadFile/WriteFile. */
  3854   3856   #endif
  3855   3857     LPVOID pOverlapped = 0;
  3856   3858     sqlite3_int64 offset = WIN_SHM_DMS;
................................................................................
  3863   3865     }
  3864   3866   #else
  3865   3867     memset(&overlapped, 0, sizeof(OVERLAPPED));
  3866   3868     overlapped.Offset = (LONG)(offset & 0xffffffff);
  3867   3869     overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
  3868   3870     pOverlapped = &overlapped;
  3869   3871   #endif
  3870         -  if( !osWriteFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
  3871         -    DWORD lastErrno = osGetLastError();
         3872  +  if( bReadOnly ||
         3873  +      !osWriteFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
         3874  +    DWORD lastErrno = bReadOnly ? NO_ERROR : osGetLastError();
  3872   3875       if( !osReadFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
  3873   3876         lastErrno = osGetLastError();
  3874   3877         if( winIsLockingError(lastErrno) ){
  3875         -        *pLockType = WINSHM_WRLCK;
         3878  +        if( pLockType ) *pLockType = WINSHM_WRLCK;
  3876   3879         }else{
  3877   3880           return SQLITE_IOERR_READ;
  3878   3881         }
  3879   3882       }else{
  3880   3883         if( winIsLockingError(lastErrno) ){
  3881         -        *pLockType = WINSHM_RDLCK;
         3884  +        if( pLockType ) *pLockType = WINSHM_RDLCK;
  3882   3885         }else{
  3883   3886           return SQLITE_IOERR_WRITE;
  3884   3887         }
  3885   3888       }
  3886   3889     }else{
  3887         -    *pLockType = WINSHM_UNLCK;
         3890  +    if( pLockType ) *pLockType = WINSHM_UNLCK;
  3888   3891     }
  3889   3892     return SQLITE_OK;
  3890   3893   }
  3891   3894   
  3892   3895   /*
  3893   3896   ** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
  3894   3897   ** take it now. Return SQLITE_OK if successful, or an SQLite error
................................................................................
  3916   3919     ** return SQLITE_BUSY to the caller (it will try again). An earlier
  3917   3920     ** version of this code attempted the SHARED lock at this point. But
  3918   3921     ** this introduced a subtle race condition: if the process holding
  3919   3922     ** EXCLUSIVE failed just before truncating the *-shm file, then this
  3920   3923     ** process might open and use the *-shm file without truncating it.
  3921   3924     ** And if the *-shm file has been corrupted by a power failure or
  3922   3925     ** system crash, the database itself may also become corrupt.  */
  3923         -  if( winGetShmDmsLockType(&pShmNode->hFile, &lockType)!=SQLITE_OK ){
         3926  +  if( winGetShmDmsLockType(&pShmNode->hFile, pShmNode->isReadonly,
         3927  +                           &lockType)!=SQLITE_OK ){
  3924   3928       rc = SQLITE_IOERR_LOCK;
  3925   3929     }else if( lockType==WINSHM_UNLCK ){
  3926   3930       if( pShmNode->isReadonly ){
  3927   3931         pShmNode->isUnlocked = 1;
  3928   3932         rc = SQLITE_READONLY_CANTINIT;
  3929   3933       }else{
  3930   3934         winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);