Revise and vastly simplify the Win32 SHM file locking semantics, allowing all new tests to pass.

FossilOrigin-Name: d0997b0f5bc9a9869684e39a17a01c430d6383c8b31d6c00ea17a5eac15bc6f0
This commit is contained in:
mistachkin 2017-11-09 22:23:50 +00:00
parent 95a05aae67
commit 7b7f224c62
3 changed files with 15 additions and 127 deletions

View File

@ -1,5 +1,5 @@
C Add\san\sassert()\sin\sthe\sWin32\sVFS.
D 2017-11-09T20:37:37.876
C Revise\sand\svastly\ssimplify\sthe\sWin32\sSHM\sfile\slocking\ssemantics,\sallowing\sall\snew\stests\sto\spass.
D 2017-11-09T22:23:50.758
F Makefile.in 5bae3f2f3d42f2ad52b141562d74872c97ac0fca6c54953c91bb150a0e6427a8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 3a5cb477ec3ce5274663b693164e349db63348667cd45bad78cc13d580b691e2
@ -448,7 +448,7 @@ F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c e87cef0bb894b94d96ee3af210be669549d111c580817d14818101b992640767
F src/os_win.c 64bc61821f75b37ca213da93aef84557c8730be6e0ca93943223b5e57fe6e5a3
F src/os_win.c b40d4f98562048b1d084b71bb08367903b937424427ee7b866902dca7b79cb88
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 07cf850241667874fcce9d7d924c814305e499b26c804322e2261247b5921903
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
@ -1669,7 +1669,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P ff630b66714b20c09888ead0a45f344d63e0d9a5208867d6266e74f79187076c
R 9f94324b020c3efbc23aa89a0c6b1ac2
P 22e58330461736ca22d6f4d7eab897a3597de2e7434a6f4a474f0f0d7f964281
R 0c5d22f8af57ea73c927075712f52c29
U mistachkin
Z b9496fb62e9a99521b89e7f9003a99d8
Z e19a1ec884226a6dec0cb1fab52ceb52

View File

@ -1 +1 @@
22e58330461736ca22d6f4d7eab897a3597de2e7434a6f4a474f0f0d7f964281
d0997b0f5bc9a9869684e39a17a01c430d6383c8b31d6c00ea17a5eac15bc6f0

View File

@ -2098,27 +2098,6 @@ static int winLogErrorAtLine(
static int winIoerrRetry = SQLITE_WIN32_IOERR_RETRY;
static int winIoerrRetryDelay = SQLITE_WIN32_IOERR_RETRY_DELAY;
/*
** The "winIsLockConflict" macro is used to determine if a particular I/O
** error code is due to a file locking conflict. It must accept the error
** code DWORD as its only argument.
*/
#if !defined(winIsLockConflict)
#define winIsLockConflict(a) (((a)==NO_ERROR) || \
((a)==ERROR_LOCK_VIOLATION) || \
((a)==ERROR_IO_PENDING))
#endif
/*
** The "winIsLockMissing" macro is used to determine if a particular I/O
** error code is due to being unable to obtain a file lock because all or
** part of the range requested within the file is missing. It must accept
** the error code DWORD as its only argument.
*/
#if !defined(winIsLockMissing)
#define winIsLockMissing(a) (((a)==ERROR_HANDLE_EOF))
#endif
/*
** The "winIoerrCanRetry1" macro is used to determine if a particular I/O
** error code obtained via GetLastError() is eligible to be retried. It
@ -3844,65 +3823,6 @@ static void winShmPurge(sqlite3_vfs *pVfs, int deleteFlag){
}
}
/*
** Query the status of the DMS lock for the specified file. Returns
** SQLITE_OK upon success. Upon success, the integer pointed to by
** the pLockType argument will be set to the lock type held by the
** other process, as follows:
**
** WINSHM_UNLCK -- No locks are held on the DMS.
** WINSHM_RDLCK -- A SHARED lock is held on the DMS.
** WINSHM_WRLCK -- An EXCLUSIVE lock is held on the DMS.
*/
static int winGetShmDmsLockType(
winFile *pFile, /* File handle object */
int bReadOnly, /* Non-zero if the SHM was opened read-only */
int *pLockType /* WINSHM_UNLCK, WINSHM_RDLCK, or WINSHM_WRLCK */
){
#if !SQLITE_OS_WINCE && !defined(SQLITE_WIN32_NO_OVERLAPPED)
OVERLAPPED overlapped; /* The offset for ReadFile/WriteFile. */
#endif
LPVOID pOverlapped = 0;
sqlite3_int64 offset = WIN_SHM_DMS;
BYTE notUsed1 = 0;
DWORD notUsed2 = 0;
#if SQLITE_OS_WINCE || defined(SQLITE_WIN32_NO_OVERLAPPED)
if( winSeekFile(pFile, offset) ){
return SQLITE_IOERR_SEEK;
}
#else
memset(&overlapped, 0, sizeof(OVERLAPPED));
overlapped.Offset = (LONG)(offset & 0xffffffff);
overlapped.OffsetHigh = (LONG)((offset>>32) & 0x7fffffff);
pOverlapped = &overlapped;
#endif
if( bReadOnly ||
!osWriteFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
DWORD lastErrno = bReadOnly ? NO_ERROR : osGetLastError();
if( !osReadFile(pFile->h, &notUsed1, 1, &notUsed2, pOverlapped) ){
lastErrno = osGetLastError();
if( winIsLockConflict(lastErrno) ){
if( pLockType ) *pLockType = WINSHM_WRLCK;
}else if( winIsLockMissing(lastErrno) ){
assert( bReadOnly );
if( pLockType ) *pLockType = WINSHM_UNLCK;
}else{
return SQLITE_IOERR_READ;
}
}else{
if( winIsLockConflict(lastErrno) ){
if( pLockType ) *pLockType = WINSHM_RDLCK;
}else{
return SQLITE_IOERR_WRITE;
}
}
}else{
if( pLockType ) *pLockType = WINSHM_UNLCK;
}
return SQLITE_OK;
}
/*
** The DMS lock has not yet been taken on shm file pShmNode. Attempt to
** take it now. Return SQLITE_OK if successful, or an SQLite error
@ -3913,53 +3833,21 @@ static int winGetShmDmsLockType(
** SQLITE_READONLY_CANTINIT and set pShmNode->isUnlocked=1.
*/
static int winLockSharedMemory(winShmNode *pShmNode){
int lockType;
int rc = SQLITE_OK;
/* Use ReadFile/WriteFile to determine the locks other processes are
** holding on the DMS byte. If it indicates that another process is
** holding a SHARED lock, then this process may also take a SHARED
** lock and proceed with opening the *-shm file.
**
** Or, if no other process is holding any lock, then this process
** is the first to open it. In this case take an EXCLUSIVE lock on the
** DMS byte and truncate the *-shm file to zero bytes in size. Then
** downgrade to a SHARED lock on the DMS byte.
**
** If another process is holding an EXCLUSIVE lock on the DMS byte,
** return SQLITE_BUSY to the caller (it will try again). An earlier
** version of this code attempted the SHARED lock at this point. But
** this introduced a subtle race condition: if the process holding
** EXCLUSIVE failed just before truncating the *-shm file, then this
** process might open and use the *-shm file without truncating it.
** And if the *-shm file has been corrupted by a power failure or
** system crash, the database itself may also become corrupt. */
if( winGetShmDmsLockType(&pShmNode->hFile, pShmNode->isReadonly,
&lockType)!=SQLITE_OK ){
rc = SQLITE_IOERR_LOCK;
}else if( lockType==WINSHM_UNLCK ){
int rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
if( rc==SQLITE_OK ){
if( pShmNode->isReadonly ){
pShmNode->isUnlocked = 1;
rc = SQLITE_READONLY_CANTINIT;
}else{
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_WRLCK, WIN_SHM_DMS, 1);
if( rc==SQLITE_OK && winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
rc = winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
return SQLITE_READONLY_CANTINIT;
}else if( winTruncate((sqlite3_file*)&pShmNode->hFile, 0) ){
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
return winLogError(SQLITE_IOERR_SHMOPEN, osGetLastError(),
"winLockSharedMemory", pShmNode->zFilename);
}
}
}else if( lockType==WINSHM_WRLCK ){
rc = SQLITE_BUSY;
}
if( rc==SQLITE_OK ){
assert( lockType==WINSHM_UNLCK || lockType==WINSHM_RDLCK );
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
rc = winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
return rc;
winShmSystemLock(pShmNode, WINSHM_UNLCK, WIN_SHM_DMS, 1);
return winShmSystemLock(pShmNode, WINSHM_RDLCK, WIN_SHM_DMS, 1);
}
/*