/ Check-in [d0997b0f]
Login

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

Overview
Comment:Revise and vastly simplify the Win32 SHM file locking semantics, allowing all new tests to pass.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | readonly-wal-recovery
Files: files | file ages | folders
SHA3-256: d0997b0f5bc9a9869684e39a17a01c430d6383c8b31d6c00ea17a5eac15bc6f0
User & Date: mistachkin 2017-11-09 22:23:50
Context
2017-11-09
22:25
Cleanup superfluous whitespace changes. check-in: a2908e2c user: mistachkin tags: readonly-wal-recovery
22:23
Revise and vastly simplify the Win32 SHM file locking semantics, allowing all new tests to pass. check-in: d0997b0f user: mistachkin tags: readonly-wal-recovery
20:37
Add an assert() in the Win32 VFS. check-in: 22e58330 user: mistachkin tags: readonly-wal-recovery
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/os_win.c.

  2094   2094   #endif
  2095   2095   #ifndef SQLITE_WIN32_IOERR_RETRY_DELAY
  2096   2096   # define SQLITE_WIN32_IOERR_RETRY_DELAY 25
  2097   2097   #endif
  2098   2098   static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
  2099   2099   static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
  2100   2100   
  2101         -/*
  2102         -** The "winIsLockConflict" macro is used to determine if a particular I/O
  2103         -** error code is due to a file locking conflict.  It must accept the error
  2104         -** code DWORD as its only argument.
  2105         -*/
  2106         -#if !defined(winIsLockConflict)
  2107         -#define winIsLockConflict(a) (((a)==NO_ERROR)                   || \
  2108         -                              ((a)==ERROR_LOCK_VIOLATION)       || \
  2109         -                              ((a)==ERROR_IO_PENDING))
  2110         -#endif
  2111         -
  2112         -/*
  2113         -** The "winIsLockMissing" macro is used to determine if a particular I/O
  2114         -** error code is due to being unable to obtain a file lock because all or
  2115         -** part of the range requested within the file is missing.  It must accept
  2116         -** the error code DWORD as its only argument.
  2117         -*/
  2118         -#if !defined(winIsLockMissing)
  2119         -#define winIsLockMissing(a) (((a)==ERROR_HANDLE_EOF))
  2120         -#endif
  2121         -
  2122   2101   /*
  2123   2102   ** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
  2124   2103   ** error code obtained via GetLastError() is eligible to be retried.  It
  2125   2104   ** must accept the error code DWORD as its only argument and should return
  2126   2105   ** non-zero if the error code is transient in nature and the operation
  2127   2106   ** responsible for generating the original error might succeed upon being
  2128   2107   ** retried.  The argument to this macro should be a variable.
................................................................................
  3840   3819         sqlite3_free(p);
  3841   3820       }else{
  3842   3821         pp = &p->pNext;
  3843   3822       }
  3844   3823     }
  3845   3824   }
  3846   3825   
  3847         -/*
  3848         -** Query the status of the DMS lock for the specified file.  Returns
  3849         -** SQLITE_OK upon success.  Upon success, the integer pointed to by
  3850         -** the pLockType argument will be set to the lock type held by the
  3851         -** other process, as follows:
  3852         -**
  3853         -**       WINSHM_UNLCK -- No locks are held on the DMS.
  3854         -**       WINSHM_RDLCK -- A SHARED lock is held on the DMS.
  3855         -**       WINSHM_WRLCK -- An EXCLUSIVE lock is held on the DMS.
  3856         -*/
  3857         -static int winGetShmDmsLockType(
  3858         -  winFile *pFile, /* File handle object */
  3859         -  int bReadOnly,  /* Non-zero if the SHM was opened read-only */
  3860         -  int *pLockType  /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
  3861         -){
  3862         -#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
  3863         -  OVERLAPPED overlapped; /* The offset for ReadFile/WriteFile. */
  3864         -#endif
  3865         -  LPVOID pOverlapped = 0;
  3866         -  sqlite3_int64 offset = WIN_SHM_DMS;
  3867         -  BYTE notUsed1 = 0;
  3868         -  DWORD notUsed2 = 0;
  3869         -
  3870         -#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
  3871         -  if( winSeekFile(pFile, offset) ){
  3872         -    return SQLITE_IOERR_SEEK;
  3873         -  }
  3874         -#else
  3875         -  memset(&overlapped, 0, sizeof(OVERLAPPED));
  3876         -  overlapped.Offset = (LONG)(offset & 0xffffffff);
  3877         -  overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
  3878         -  pOverlapped = &overlapped;
  3879         -#endif
  3880         -  if( bReadOnly ||
  3881         -      !osWriteFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
  3882         -    DWORD lastErrno = bReadOnly ? NO_ERROR : osGetLastError();
  3883         -    if( !osReadFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
  3884         -      lastErrno = osGetLastError();
  3885         -      if( winIsLockConflict(lastErrno) ){
  3886         -        if( pLockType ) *pLockType = WINSHM_WRLCK;
  3887         -      }else if( winIsLockMissing(lastErrno) ){
  3888         -        assert( bReadOnly );
  3889         -        if( pLockType ) *pLockType = WINSHM_UNLCK;
  3890         -      }else{
  3891         -        return SQLITE_IOERR_READ;
  3892         -      }
  3893         -    }else{
  3894         -      if( winIsLockConflict(lastErrno) ){
  3895         -        if( pLockType ) *pLockType = WINSHM_RDLCK;
  3896         -      }else{
  3897         -        return SQLITE_IOERR_WRITE;
  3898         -      }
  3899         -    }
  3900         -  }else{
  3901         -    if( pLockType ) *pLockType = WINSHM_UNLCK;
  3902         -  }
  3903         -  return SQLITE_OK;
  3904         -}
  3905         -
  3906   3826   /*
  3907   3827   ** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
  3908   3828   ** take it now. Return SQLITE_OK if successful, or an SQLite error
  3909   3829   ** code otherwise.
  3910   3830   **
  3911   3831   ** If the DMS cannot be locked because this is a readonly_shm=1
  3912   3832   ** connection and no other process already holds a lock, return
  3913   3833   ** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
  3914   3834   */
  3915   3835   static int winLockSharedMemory(winShmNode *pShmNode){
  3916         -  int lockType;
  3917         -  int rc = SQLITE_OK;
  3918         -
  3919         -  /* Use ReadFile/WriteFile to determine the locks other processes are
  3920         -  ** holding on the DMS byte. If it indicates that another process is
  3921         -  ** holding a SHARED lock, then this process may also take a SHARED
  3922         -  ** lock and proceed with opening the *-shm file.
  3923         -  **
  3924         -  ** Or, if no other process is holding any lock, then this process
  3925         -  ** is the first to open it. In this case take an EXCLUSIVE lock on the
  3926         -  ** DMS byte and truncate the *-shm file to zero bytes in size. Then
  3927         -  ** downgrade to a SHARED lock on the DMS byte.
  3928         -  **
  3929         -  ** If another process is holding an EXCLUSIVE lock on the DMS byte,
  3930         -  ** return SQLITE_BUSY to the caller (it will try again). An earlier
  3931         -  ** version of this code attempted the SHARED lock at this point. But
  3932         -  ** this introduced a subtle race condition: if the process holding
  3933         -  ** EXCLUSIVE failed just before truncating the *-shm file, then this
  3934         -  ** process might open and use the *-shm file without truncating it.
  3935         -  ** And if the *-shm file has been corrupted by a power failure or
  3936         -  ** system crash, the database itself may also become corrupt.  */
  3937         -  if( winGetShmDmsLockType(&pShmNode->hFile, pShmNode->isReadonly,
  3938         -                           &lockType)!=SQLITE_OK ){
  3939         -    rc = SQLITE_IOERR_LOCK;
  3940         -  }else if( lockType==WINSHM_UNLCK ){
         3836  +  int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
         3837  +  if( rc==SQLITE_OK ){
  3941   3838       if( pShmNode->isReadonly ){
  3942   3839         pShmNode->isUnlocked = 1;
  3943         -      rc = SQLITE_READONLY_CANTINIT;
  3944         -    }else{
         3840  +      winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
         3841  +      return SQLITE_READONLY_CANTINIT;
         3842  +    }else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
  3945   3843         winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
  3946         -      rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
  3947         -      if( rc==SQLITE_OK && winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
  3948         -        rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
         3844  +      return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
  3949   3845                            "winLockSharedMemory", pShmNode->zFilename);
  3950         -      }
  3951   3846       }
  3952         -  }else if( lockType==WINSHM_WRLCK ){
  3953         -    rc = SQLITE_BUSY;
  3954   3847     }
  3955   3848   
  3956         -  if( rc==SQLITE_OK ){
  3957         -    assert( lockType==WINSHM_UNLCK || lockType==WINSHM_RDLCK );
  3958         -    winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
  3959         -    rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
  3960         -  }
  3961         -
  3962         -  return rc;
         3849  +  winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
         3850  +  return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
  3963   3851   }
  3964   3852   
  3965   3853   /*
  3966   3854   ** Open the shared-memory area associated with database file pDbFd.
  3967   3855   **
  3968   3856   ** When opening a new shared-memory file, if no other instances of that
  3969   3857   ** file are currently open, in this process or in other processes, then